From d9336056d7694348ee7db3da27f06c821cd35112 Mon Sep 17 00:00:00 2001 From: Pranav Salunke Date: Sat, 10 Oct 2015 09:03:51 +0200 Subject: [PATCH] Update .gitignore to track the lib folder Allows content in the lib folder to be tracked by the repository. Change-Id: I46ae209daba8d109ed4cf4d8ca3094404e1524ee --- .gitignore | 14 +- labs/osbash/lib/README.rst | 9 + labs/osbash/lib/functions-common-devstack | 1630 +++++++++++++++++ labs/osbash/lib/functions.guest | 441 +++++ labs/osbash/lib/functions.sh | 91 + labs/osbash/lib/osbash-ssh-keys/README.rst | 2 + labs/osbash/lib/osbash-ssh-keys/osbash_key | 27 + .../osbash/lib/osbash-ssh-keys/osbash_key.pub | 1 + labs/osbash/lib/osbash/functions-host.sh | 460 +++++ labs/osbash/lib/osbash/lib-color.sh | 54 + labs/osbash/lib/osbash/lib.fedora-20-x86_64 | 43 + .../osbash/lib.ubuntu-12.04.4-server-amd64 | 53 + .../lib/osbash/lib.ubuntu-14.04-server-amd64 | 53 + labs/osbash/lib/osbash/netboot/ks-all-v2.cfg | 75 + labs/osbash/lib/osbash/netboot/ks-all.cfg | 75 + labs/osbash/lib/osbash/netboot/ks-ssh-v2.cfg | 58 + labs/osbash/lib/osbash/netboot/ks-ssh.cfg | 58 + labs/osbash/lib/osbash/netboot/ks-vbadd.cfg | 64 + .../lib/osbash/netboot/preseed-all-v2.cfg | 120 ++ .../osbash/lib/osbash/netboot/preseed-all.cfg | 120 ++ .../lib/osbash/netboot/preseed-ssh-v2.cfg | 120 ++ .../osbash/lib/osbash/netboot/preseed-ssh.cfg | 120 ++ .../lib/osbash/netboot/preseed-vbadd.cfg | 120 ++ labs/osbash/lib/osbash/scanlib.sh | 302 +++ .../templates/template-fedora-ifcfg-hostonly | 5 + .../templates/template-fedora-ifcfg-nat | 4 + .../template-ubuntu-interfaces-hostonly | 4 + .../template-ubuntu-interfaces-loopback | 3 + .../templates/template-ubuntu-interfaces-nat | 3 + .../osbash/lib/osbash/virtualbox-functions.sh | 738 ++++++++ .../lib/osbash/virtualbox-install_base.sh | 145 ++ .../lib/osbash/virtualbox-install_nodes.sh | 86 + labs/osbash/lib/wbatch/README.rst | 2 + labs/osbash/lib/wbatch/batch_for_windows.sh | 298 +++ .../osbash/lib/wbatch/template-begin_base_bat | 37 + .../osbash/lib/wbatch/template-begin_node_bat | 23 + .../lib/wbatch/template-create_hostnet_bat | 31 + .../lib/wbatch/template-elevate_privs_bat | 26 + labs/osbash/lib/wbatch/template-end_file_bat | 59 + .../lib/wbatch/template-file_header_bat | 16 + labs/osbash/lib/wbatch/template-find_vbm_bat | 30 + labs/osbash/lib/wbatch/template-mkdirs_bat | 20 + 42 files changed, 5632 insertions(+), 8 deletions(-) create mode 100644 labs/osbash/lib/README.rst create mode 100644 labs/osbash/lib/functions-common-devstack create mode 100644 labs/osbash/lib/functions.guest create mode 100644 labs/osbash/lib/functions.sh create mode 100644 labs/osbash/lib/osbash-ssh-keys/README.rst create mode 100644 labs/osbash/lib/osbash-ssh-keys/osbash_key create mode 100644 labs/osbash/lib/osbash-ssh-keys/osbash_key.pub create mode 100644 labs/osbash/lib/osbash/functions-host.sh create mode 100644 labs/osbash/lib/osbash/lib-color.sh create mode 100644 labs/osbash/lib/osbash/lib.fedora-20-x86_64 create mode 100644 labs/osbash/lib/osbash/lib.ubuntu-12.04.4-server-amd64 create mode 100644 labs/osbash/lib/osbash/lib.ubuntu-14.04-server-amd64 create mode 100644 labs/osbash/lib/osbash/netboot/ks-all-v2.cfg create mode 100644 labs/osbash/lib/osbash/netboot/ks-all.cfg create mode 100644 labs/osbash/lib/osbash/netboot/ks-ssh-v2.cfg create mode 100644 labs/osbash/lib/osbash/netboot/ks-ssh.cfg create mode 100644 labs/osbash/lib/osbash/netboot/ks-vbadd.cfg create mode 100644 labs/osbash/lib/osbash/netboot/preseed-all-v2.cfg create mode 100644 labs/osbash/lib/osbash/netboot/preseed-all.cfg create mode 100644 labs/osbash/lib/osbash/netboot/preseed-ssh-v2.cfg create mode 100644 labs/osbash/lib/osbash/netboot/preseed-ssh.cfg create mode 100644 labs/osbash/lib/osbash/netboot/preseed-vbadd.cfg create mode 100644 labs/osbash/lib/osbash/scanlib.sh create mode 100644 labs/osbash/lib/osbash/templates/template-fedora-ifcfg-hostonly create mode 100644 labs/osbash/lib/osbash/templates/template-fedora-ifcfg-nat create mode 100644 labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-hostonly create mode 100644 labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-loopback create mode 100644 labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-nat create mode 100644 labs/osbash/lib/osbash/virtualbox-functions.sh create mode 100644 labs/osbash/lib/osbash/virtualbox-install_base.sh create mode 100644 labs/osbash/lib/osbash/virtualbox-install_nodes.sh create mode 100644 labs/osbash/lib/wbatch/README.rst create mode 100644 labs/osbash/lib/wbatch/batch_for_windows.sh create mode 100644 labs/osbash/lib/wbatch/template-begin_base_bat create mode 100644 labs/osbash/lib/wbatch/template-begin_node_bat create mode 100644 labs/osbash/lib/wbatch/template-create_hostnet_bat create mode 100644 labs/osbash/lib/wbatch/template-elevate_privs_bat create mode 100644 labs/osbash/lib/wbatch/template-end_file_bat create mode 100644 labs/osbash/lib/wbatch/template-file_header_bat create mode 100644 labs/osbash/lib/wbatch/template-find_vbm_bat create mode 100644 labs/osbash/lib/wbatch/template-mkdirs_bat diff --git a/.gitignore b/.gitignore index c806f2f1..97b93753 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,6 @@ var sdist develop-eggs .installed.cfg -lib -lib64 # Installer logs pip-log.txt @@ -60,9 +58,9 @@ tenvironment .ropeproject/ # Labs artifacts -labs/autostart -labs/img -labs/log -labs/wbatch -labs/lib/vagrant-ssh-keys -labs/test_tmp/ +labs/osbash/autostart/ +labs/osbash/img/ +labs/osbash/log/ +labs/osbash/wbatch/ +labs/osbash/lib/vagrant-ssh-keys/ +labs/osbash/test_tmp/ diff --git a/labs/osbash/lib/README.rst b/labs/osbash/lib/README.rst new file mode 100644 index 00000000..a72fc822 --- /dev/null +++ b/labs/osbash/lib/README.rst @@ -0,0 +1,9 @@ +This directory contains bash libraries used by scripts. + +Configuration files for kickstart (Fedora) and preseed (Ubuntu) are in +osbash/netboot. + +The osbash-ssh-keys can be automatically installed into osbash +VMs to make them accessible. + +The templates used to build Windows batch files are in the wbatch subdirectory. diff --git a/labs/osbash/lib/functions-common-devstack b/labs/osbash/lib/functions-common-devstack new file mode 100644 index 00000000..cc90c073 --- /dev/null +++ b/labs/osbash/lib/functions-common-devstack @@ -0,0 +1,1630 @@ +# functions-common - Common functions used by DevStack components +# +# The canonical copy of this file is maintained in the DevStack repo. +# All modifications should be made there and then sync'ed to other repos +# as required. +# +# This file is sorted alphabetically within the function groups. +# +# - Config Functions +# - Control Functions +# - Distro Functions +# - Git Functions +# - OpenStack Functions +# - Package Functions +# - Process Functions +# - Python Functions +# - Service Functions +# - System Functions +# +# The following variables are assumed to be defined by certain functions: +# +# - ``ENABLED_SERVICES`` +# - ``ERROR_ON_CLONE`` +# - ``FILES`` +# - ``OFFLINE`` +# - ``PIP_DOWNLOAD_CACHE`` +# - ``PIP_USE_MIRRORS`` +# - ``RECLONE`` +# - ``REQUIREMENTS_DIR`` +# - ``STACK_USER`` +# - ``TRACK_DEPENDS`` +# - ``UNDO_REQUIREMENTS`` +# - ``http_proxy``, ``https_proxy``, ``no_proxy`` + +# Save trace setting +XTRACE=$(set +o | grep xtrace) +set +o xtrace + + +# Config Functions +# ================ + +# Append a new option in an ini file without replacing the old value +# iniadd config-file section option value1 value2 value3 ... +function iniadd { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + shift 3 + local values="$(iniget_multiline $file $section $option) $@" + iniset_multiline $file $section $option $values + $xtrace +} + +# Comment an option in an INI file +# inicomment config-file section option +function inicomment { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file" + $xtrace +} + +# Get an option from an INI file +# iniget config-file section option +function iniget { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + local line + line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file") + echo ${line#*=} + $xtrace +} + +# Get a multiple line option from an INI file +# iniget_multiline config-file section option +function iniget_multiline { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + local values + values=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { s/^$option[ \t]*=[ \t]*//gp; }" "$file") + echo ${values} + $xtrace +} + +# Determinate is the given option present in the INI file +# ini_has_option config-file section option +function ini_has_option { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + local line + line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file") + $xtrace + [ -n "$line" ] +} + +# Set an option in an INI file +# iniset config-file section option value +function iniset { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + local value=$4 + + [[ -z $section || -z $option ]] && return + + if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then + # Add section at the end + echo -e "\n[$section]" >>"$file" + fi + if ! ini_has_option "$file" "$section" "$option"; then + # Add it + sed -i -e "/^\[$section\]/ a\\ +$option = $value +" "$file" + else + local sep=$(echo -ne "\x01") + # Replace it + sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('${option}'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file" + fi + $xtrace +} + +# Set a multiple line option in an INI file +# iniset_multiline config-file section option value1 value2 valu3 ... +function iniset_multiline { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + shift 3 + local values + for v in $@; do + # The later sed command inserts each new value in the line next to + # the section identifier, which causes the values to be inserted in + # the reverse order. Do a reverse here to keep the original order. + values="$v ${values}" + done + if ! grep -q "^\[$section\]" "$file"; then + # Add section at the end + echo -e "\n[$section]" >>"$file" + else + # Remove old values + sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file" + fi + # Add new ones + for v in $values; do + sed -i -e "/^\[$section\]/ a\\ +$option = $v +" "$file" + done + $xtrace +} + +# Uncomment an option in an INI file +# iniuncomment config-file section option +function iniuncomment { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" "$file" + $xtrace +} + +# Normalize config values to True or False +# Accepts as False: 0 no No NO false False FALSE +# Accepts as True: 1 yes Yes YES true True TRUE +# VAR=$(trueorfalse default-value test-value) +function trueorfalse { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local default=$1 + local testval=$2 + + [[ -z "$testval" ]] && { echo "$default"; return; } + [[ "0 no No NO false False FALSE" =~ "$testval" ]] && { echo "False"; return; } + [[ "1 yes Yes YES true True TRUE" =~ "$testval" ]] && { echo "True"; return; } + echo "$default" + $xtrace +} + + +# Control Functions +# ================= + +# Prints backtrace info +# filename:lineno:function +# backtrace level +function backtrace { + local level=$1 + local deep=$((${#BASH_SOURCE[@]} - 1)) + echo "[Call Trace]" + while [ $level -le $deep ]; do + echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}" + deep=$((deep - 1)) + done +} + +# Prints line number and "message" then exits +# die $LINENO "message" +function die { + local exitcode=$? + set +o xtrace + local line=$1; shift + if [ $exitcode == 0 ]; then + exitcode=1 + fi + backtrace 2 + err $line "$*" + # Give buffers a second to flush + sleep 1 + exit $exitcode +} + +# Checks an environment variable is not set or has length 0 OR if the +# exit code is non-zero and prints "message" and exits +# NOTE: env-var is the variable name without a '$' +# die_if_not_set $LINENO env-var "message" +function die_if_not_set { + local exitcode=$? + FXTRACE=$(set +o | grep xtrace) + set +o xtrace + local line=$1; shift + local evar=$1; shift + if ! is_set $evar || [ $exitcode != 0 ]; then + die $line "$*" + fi + $FXTRACE +} + +# Prints line number and "message" in error format +# err $LINENO "message" +function err { + local exitcode=$? + errXTRACE=$(set +o | grep xtrace) + set +o xtrace + local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2" + echo $msg 1>&2; + if [[ -n ${SCREEN_LOGDIR} ]]; then + echo $msg >> "${SCREEN_LOGDIR}/error.log" + fi + $errXTRACE + return $exitcode +} + +# Checks an environment variable is not set or has length 0 OR if the +# exit code is non-zero and prints "message" +# NOTE: env-var is the variable name without a '$' +# err_if_not_set $LINENO env-var "message" +function err_if_not_set { + local exitcode=$? + errinsXTRACE=$(set +o | grep xtrace) + set +o xtrace + local line=$1; shift + local evar=$1; shift + if ! is_set $evar || [ $exitcode != 0 ]; then + err $line "$*" + fi + $errinsXTRACE + return $exitcode +} + +# Exit after outputting a message about the distribution not being supported. +# exit_distro_not_supported [optional-string-telling-what-is-missing] +function exit_distro_not_supported { + if [[ -z "$DISTRO" ]]; then + GetDistro + fi + + if [ $# -gt 0 ]; then + die $LINENO "Support for $DISTRO is incomplete: no support for $@" + else + die $LINENO "Support for $DISTRO is incomplete." + fi +} + +# Test if the named environment variable is set and not zero length +# is_set env-var +function is_set { + local var=\$"$1" + eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this +} + +# Prints line number and "message" in warning format +# warn $LINENO "message" +function warn { + local exitcode=$? + errXTRACE=$(set +o | grep xtrace) + set +o xtrace + local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2" + echo $msg 1>&2; + if [[ -n ${SCREEN_LOGDIR} ]]; then + echo $msg >> "${SCREEN_LOGDIR}/error.log" + fi + $errXTRACE + return $exitcode +} + + +# Distro Functions +# ================ + +# Determine OS Vendor, Release and Update +# Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora +# Returns results in global variables: +# os_VENDOR - vendor name +# os_RELEASE - release +# os_UPDATE - update +# os_PACKAGE - package type +# os_CODENAME - vendor's codename for release +# GetOSVersion +function GetOSVersion { + # Figure out which vendor we are + if [[ -x "`which sw_vers 2>/dev/null`" ]]; then + # OS/X + os_VENDOR=`sw_vers -productName` + os_RELEASE=`sw_vers -productVersion` + os_UPDATE=${os_RELEASE##*.} + os_RELEASE=${os_RELEASE%.*} + os_PACKAGE="" + if [[ "$os_RELEASE" =~ "10.7" ]]; then + os_CODENAME="lion" + elif [[ "$os_RELEASE" =~ "10.6" ]]; then + os_CODENAME="snow leopard" + elif [[ "$os_RELEASE" =~ "10.5" ]]; then + os_CODENAME="leopard" + elif [[ "$os_RELEASE" =~ "10.4" ]]; then + os_CODENAME="tiger" + elif [[ "$os_RELEASE" =~ "10.3" ]]; then + os_CODENAME="panther" + else + os_CODENAME="" + fi + elif [[ -x $(which lsb_release 2>/dev/null) ]]; then + os_VENDOR=$(lsb_release -i -s) + os_RELEASE=$(lsb_release -r -s) + os_UPDATE="" + os_PACKAGE="rpm" + if [[ "Debian,Ubuntu,LinuxMint" =~ $os_VENDOR ]]; then + os_PACKAGE="deb" + elif [[ "SUSE LINUX" =~ $os_VENDOR ]]; then + lsb_release -d -s | grep -q openSUSE + if [[ $? -eq 0 ]]; then + os_VENDOR="openSUSE" + fi + elif [[ $os_VENDOR == "openSUSE project" ]]; then + os_VENDOR="openSUSE" + elif [[ $os_VENDOR =~ Red.*Hat ]]; then + os_VENDOR="Red Hat" + fi + os_CODENAME=$(lsb_release -c -s) + elif [[ -r /etc/redhat-release ]]; then + # Red Hat Enterprise Linux Server release 5.5 (Tikanga) + # Red Hat Enterprise Linux Server release 7.0 Beta (Maipo) + # CentOS release 5.5 (Final) + # CentOS Linux release 6.0 (Final) + # Fedora release 16 (Verne) + # XenServer release 6.2.0-70446c (xenenterprise) + os_CODENAME="" + for r in "Red Hat" CentOS Fedora XenServer; do + os_VENDOR=$r + if [[ -n "`grep \"$r\" /etc/redhat-release`" ]]; then + ver=`sed -e 's/^.* \([0-9].*\) (\(.*\)).*$/\1\|\2/' /etc/redhat-release` + os_CODENAME=${ver#*|} + os_RELEASE=${ver%|*} + os_UPDATE=${os_RELEASE##*.} + os_RELEASE=${os_RELEASE%.*} + break + fi + os_VENDOR="" + done + os_PACKAGE="rpm" + elif [[ -r /etc/SuSE-release ]]; then + for r in openSUSE "SUSE Linux"; do + if [[ "$r" = "SUSE Linux" ]]; then + os_VENDOR="SUSE LINUX" + else + os_VENDOR=$r + fi + + if [[ -n "`grep \"$r\" /etc/SuSE-release`" ]]; then + os_CODENAME=`grep "CODENAME = " /etc/SuSE-release | sed 's:.* = ::g'` + os_RELEASE=`grep "VERSION = " /etc/SuSE-release | sed 's:.* = ::g'` + os_UPDATE=`grep "PATCHLEVEL = " /etc/SuSE-release | sed 's:.* = ::g'` + break + fi + os_VENDOR="" + done + os_PACKAGE="rpm" + # If lsb_release is not installed, we should be able to detect Debian OS + elif [[ -f /etc/debian_version ]] && [[ $(cat /proc/version) =~ "Debian" ]]; then + os_VENDOR="Debian" + os_PACKAGE="deb" + os_CODENAME=$(awk '/VERSION=/' /etc/os-release | sed 's/VERSION=//' | sed -r 's/\"|\(|\)//g' | awk '{print $2}') + os_RELEASE=$(awk '/VERSION_ID=/' /etc/os-release | sed 's/VERSION_ID=//' | sed 's/\"//g') + fi + export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME +} + +# Translate the OS version values into common nomenclature +# Sets global ``DISTRO`` from the ``os_*`` values +function GetDistro { + GetOSVersion + if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then + # 'Everyone' refers to Ubuntu / Debian releases by the code name adjective + DISTRO=$os_CODENAME + elif [[ "$os_VENDOR" =~ (Fedora) ]]; then + # For Fedora, just use 'f' and the release + DISTRO="f$os_RELEASE" + elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then + DISTRO="opensuse-$os_RELEASE" + elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then + # For SLE, also use the service pack + if [[ -z "$os_UPDATE" ]]; then + DISTRO="sle${os_RELEASE}" + else + DISTRO="sle${os_RELEASE}sp${os_UPDATE}" + fi + elif [[ "$os_VENDOR" =~ (Red Hat) || "$os_VENDOR" =~ (CentOS) ]]; then + # Drop the . release as we assume it's compatible + DISTRO="rhel${os_RELEASE::1}" + elif [[ "$os_VENDOR" =~ (XenServer) ]]; then + DISTRO="xs$os_RELEASE" + else + # Catch-all for now is Vendor + Release + Update + DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE" + fi + export DISTRO +} + +# Utility function for checking machine architecture +# is_arch arch-type +function is_arch { + ARCH_TYPE=$1 + + [[ "$(uname -m)" == "$ARCH_TYPE" ]] +} + +# Determine if current distribution is a Fedora-based distribution +# (Fedora, RHEL, CentOS, etc). +# is_fedora +function is_fedora { + if [[ -z "$os_VENDOR" ]]; then + GetOSVersion + fi + + [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ] +} + + +# Determine if current distribution is a SUSE-based distribution +# (openSUSE, SLE). +# is_suse +function is_suse { + if [[ -z "$os_VENDOR" ]]; then + GetOSVersion + fi + + [ "$os_VENDOR" = "openSUSE" ] || [ "$os_VENDOR" = "SUSE LINUX" ] +} + + +# Determine if current distribution is an Ubuntu-based distribution +# It will also detect non-Ubuntu but Debian-based distros +# is_ubuntu +function is_ubuntu { + if [[ -z "$os_PACKAGE" ]]; then + GetOSVersion + fi + [ "$os_PACKAGE" = "deb" ] +} + + +# Git Functions +# ============= + +# Returns openstack release name for a given branch name +# ``get_release_name_from_branch branch-name`` +function get_release_name_from_branch { + local branch=$1 + if [[ $branch =~ "stable/" ]]; then + echo ${branch#*/} + else + echo "master" + fi +} + +# git clone only if directory doesn't exist already. Since ``DEST`` might not +# be owned by the installation user, we create the directory and change the +# ownership to the proper user. +# Set global RECLONE=yes to simulate a clone when dest-dir exists +# Set global ERROR_ON_CLONE=True to abort execution with an error if the git repo +# does not exist (default is False, meaning the repo will be cloned). +# Uses global ``OFFLINE`` +# git_clone remote dest-dir branch +function git_clone { + GIT_REMOTE=$1 + GIT_DEST=$2 + GIT_REF=$3 + RECLONE=$(trueorfalse False $RECLONE) + local orig_dir=`pwd` + + if [[ "$OFFLINE" = "True" ]]; then + echo "Running in offline mode, clones already exist" + # print out the results so we know what change was used in the logs + cd $GIT_DEST + git show --oneline | head -1 + cd $orig_dir + return + fi + + if echo $GIT_REF | egrep -q "^refs"; then + # If our branch name is a gerrit style refs/changes/... + if [[ ! -d $GIT_DEST ]]; then + [[ "$ERROR_ON_CLONE" = "True" ]] && \ + die $LINENO "Cloning not allowed in this configuration" + git_timed clone $GIT_REMOTE $GIT_DEST + fi + cd $GIT_DEST + git_timed fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD + else + # do a full clone only if the directory doesn't exist + if [[ ! -d $GIT_DEST ]]; then + [[ "$ERROR_ON_CLONE" = "True" ]] && \ + die $LINENO "Cloning not allowed in this configuration" + git_timed clone $GIT_REMOTE $GIT_DEST + cd $GIT_DEST + # This checkout syntax works for both branches and tags + git checkout $GIT_REF + elif [[ "$RECLONE" = "True" ]]; then + # if it does exist then simulate what clone does if asked to RECLONE + cd $GIT_DEST + # set the url to pull from and fetch + git remote set-url origin $GIT_REMOTE + git_timed fetch origin + # remove the existing ignored files (like pyc) as they cause breakage + # (due to the py files having older timestamps than our pyc, so python + # thinks the pyc files are correct using them) + find $GIT_DEST -name '*.pyc' -delete + + # handle GIT_REF accordingly to type (tag, branch) + if [[ -n "`git show-ref refs/tags/$GIT_REF`" ]]; then + git_update_tag $GIT_REF + elif [[ -n "`git show-ref refs/heads/$GIT_REF`" ]]; then + git_update_branch $GIT_REF + elif [[ -n "`git show-ref refs/remotes/origin/$GIT_REF`" ]]; then + git_update_remote_branch $GIT_REF + else + die $LINENO "$GIT_REF is neither branch nor tag" + fi + + fi + fi + + # print out the results so we know what change was used in the logs + cd $GIT_DEST + git show --oneline | head -1 + cd $orig_dir +} + +# 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. GIT_TIMEOUT, if set, is passed directly +# to timeout(1); otherwise the default value of 0 maintains the status +# quo of waiting forever. +# usage: git_timed +function git_timed { + local count=0 + local timeout=0 + + if [[ -n "${GIT_TIMEOUT}" ]]; then + timeout=${GIT_TIMEOUT} + fi + + until timeout -s SIGINT ${timeout} git "$@"; do + # 124 is timeout(1)'s special return code when it reached the + # timeout; otherwise assume fatal failure + if [[ $? -ne 124 ]]; then + die $LINENO "git call failed: [git $@]" + fi + + count=$(($count + 1)) + warn "timeout ${count} for git call: [git $@]" + if [ $count -eq 3 ]; then + die $LINENO "Maximum of 3 git retries reached" + fi + sleep 5 + done +} + +# git update using reference as a branch. +# git_update_branch ref +function git_update_branch { + + GIT_BRANCH=$1 + + git checkout -f origin/$GIT_BRANCH + # a local branch might not exist + git branch -D $GIT_BRANCH || true + git checkout -b $GIT_BRANCH +} + +# git update using reference as a branch. +# git_update_remote_branch ref +function git_update_remote_branch { + + GIT_BRANCH=$1 + + git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH +} + +# git update using reference as a tag. Be careful editing source at that repo +# as working copy will be in a detached mode +# git_update_tag ref +function git_update_tag { + + GIT_TAG=$1 + + git tag -d $GIT_TAG + # fetching given tag only + git_timed fetch origin tag $GIT_TAG + git checkout -f $GIT_TAG +} + + +# OpenStack Functions +# =================== + +# Get the default value for HOST_IP +# get_default_host_ip fixed_range floating_range host_ip_iface host_ip +function get_default_host_ip { + local fixed_range=$1 + local floating_range=$2 + local host_ip_iface=$3 + local host_ip=$4 + + # Find the interface used for the default route + host_ip_iface=${host_ip_iface:-$(ip route | sed -n '/^default/{ s/.*dev \(\w\+\)\s\+.*/\1/; p; }' | head -1)} + # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable + if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then + host_ip="" + host_ips=`LC_ALL=C ip -f inet addr show ${host_ip_iface} | awk '/inet/ {split($2,parts,"/"); print parts[1]}'` + for IP in $host_ips; do + # Attempt to filter out IP addresses that are part of the fixed and + # floating range. Note that this method only works if the ``netaddr`` + # python library is installed. If it is not installed, an error + # will be printed and the first IP from the interface will be used. + # If that is not correct set ``HOST_IP`` in ``localrc`` to the correct + # address. + if ! (address_in_net $IP $fixed_range || address_in_net $IP $floating_range); then + host_ip=$IP + break; + fi + done + fi + echo $host_ip +} + +# Grab a numbered field from python prettytable output +# Fields are numbered starting with 1 +# Reverse syntax is supported: -1 is the last field, -2 is second to last, etc. +# get_field field-number +function get_field { + while read data; do + if [ "$1" -lt 0 ]; then + field="(\$(NF$1))" + else + field="\$$(($1 + 1))" + fi + echo "$data" | awk -F'[ \t]*\\|[ \t]*' "{print $field}" + done +} + +# Add a policy to a policy.json file +# Do nothing if the policy already exists +# ``policy_add policy_file policy_name policy_permissions`` +function policy_add { + local policy_file=$1 + local policy_name=$2 + local policy_perm=$3 + + if grep -q ${policy_name} ${policy_file}; then + echo "Policy ${policy_name} already exists in ${policy_file}" + return + fi + + # Add a terminating comma to policy lines without one + # Remove the closing '}' and all lines following to the end-of-file + local tmpfile=$(mktemp) + uniq ${policy_file} | sed -e ' + s/]$/],/ + /^[}]/,$d + ' > ${tmpfile} + + # Append policy and closing brace + echo " \"${policy_name}\": ${policy_perm}" >>${tmpfile} + echo "}" >>${tmpfile} + + mv ${tmpfile} ${policy_file} +} + + +# Package Functions +# ================= + +# _get_package_dir +function _get_package_dir { + local pkg_dir + if is_ubuntu; then + pkg_dir=$FILES/apts + elif is_fedora; then + pkg_dir=$FILES/rpms + elif is_suse; then + pkg_dir=$FILES/rpms-suse + else + exit_distro_not_supported "list of packages" + fi + echo "$pkg_dir" +} + +# Wrapper for ``apt-get`` to set cache and proxy environment variables +# Uses globals ``OFFLINE``, ``*_proxy`` +# apt_get operation package [package ...] +function apt_get { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + + [[ "$OFFLINE" = "True" || -z "$@" ]] && return + local sudo="sudo" + [[ "$(id -u)" = "0" ]] && sudo="env" + + $xtrace + $sudo DEBIAN_FRONTEND=noninteractive \ + http_proxy=$http_proxy https_proxy=$https_proxy \ + no_proxy=$no_proxy \ + apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@" +} + +# get_packages() collects a list of package names of any type from the +# prerequisite files in ``files/{apts|rpms}``. The list is intended +# to be passed to a package installer such as apt or yum. +# +# Only packages required for the services in 1st argument will be +# included. Two bits of metadata are recognized in the prerequisite files: +# +# - ``# NOPRIME`` defers installation to be performed later in `stack.sh` +# - ``# dist:DISTRO`` or ``dist:DISTRO1,DISTRO2`` limits the selection +# of the package to the distros listed. The distro names are case insensitive. +function get_packages { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local services=$@ + local package_dir=$(_get_package_dir) + local file_to_parse + local service + + if [[ -z "$package_dir" ]]; then + echo "No package directory supplied" + return 1 + fi + if [[ -z "$DISTRO" ]]; then + GetDistro + echo "Found Distro $DISTRO" + fi + for service in ${services//,/ }; do + # Allow individual services to specify dependencies + if [[ -e ${package_dir}/${service} ]]; then + file_to_parse="${file_to_parse} $service" + fi + # NOTE(sdague) n-api needs glance for now because that's where + # glance client is + if [[ $service == n-api ]]; then + if [[ ! $file_to_parse =~ nova ]]; then + file_to_parse="${file_to_parse} nova" + fi + if [[ ! $file_to_parse =~ glance ]]; then + file_to_parse="${file_to_parse} glance" + fi + elif [[ $service == c-* ]]; then + if [[ ! $file_to_parse =~ cinder ]]; then + file_to_parse="${file_to_parse} cinder" + fi + elif [[ $service == ceilometer-* ]]; then + if [[ ! $file_to_parse =~ ceilometer ]]; then + file_to_parse="${file_to_parse} ceilometer" + fi + elif [[ $service == s-* ]]; then + if [[ ! $file_to_parse =~ swift ]]; then + file_to_parse="${file_to_parse} swift" + fi + elif [[ $service == n-* ]]; then + if [[ ! $file_to_parse =~ nova ]]; then + file_to_parse="${file_to_parse} nova" + fi + elif [[ $service == g-* ]]; then + if [[ ! $file_to_parse =~ glance ]]; then + file_to_parse="${file_to_parse} glance" + fi + elif [[ $service == key* ]]; then + if [[ ! $file_to_parse =~ keystone ]]; then + file_to_parse="${file_to_parse} keystone" + fi + elif [[ $service == q-* ]]; then + if [[ ! $file_to_parse =~ neutron ]]; then + file_to_parse="${file_to_parse} neutron" + fi + elif [[ $service == ir-* ]]; then + if [[ ! $file_to_parse =~ ironic ]]; then + file_to_parse="${file_to_parse} ironic" + fi + fi + done + + for file in ${file_to_parse}; do + local fname=${package_dir}/${file} + local OIFS line package distros distro + [[ -e $fname ]] || continue + + OIFS=$IFS + IFS=$'\n' + for line in $(<${fname}); do + if [[ $line =~ "NOPRIME" ]]; then + continue + fi + + # Assume we want this package + package=${line%#*} + inst_pkg=1 + + # Look for # dist:xxx in comment + if [[ $line =~ (.*)#.*dist:([^ ]*) ]]; then + # We are using BASH regexp matching feature. + package=${BASH_REMATCH[1]} + distros=${BASH_REMATCH[2]} + # In bash ${VAR,,} will lowecase VAR + # Look for a match in the distro list + if [[ ! ${distros,,} =~ ${DISTRO,,} ]]; then + # If no match then skip this package + inst_pkg=0 + fi + fi + + # Look for # testonly in comment + if [[ $line =~ (.*)#.*testonly.* ]]; then + package=${BASH_REMATCH[1]} + # Are we installing test packages? (test for the default value) + if [[ $INSTALL_TESTONLY_PACKAGES = "False" ]]; then + # If not installing test packages the skip this package + inst_pkg=0 + fi + fi + + if [[ $inst_pkg = 1 ]]; then + echo $package + fi + done + IFS=$OIFS + done + $xtrace +} + +# Distro-agnostic package installer +# install_package package [package ...] +function install_package { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + if is_ubuntu; then + # if there are transient errors pulling the updates, that's fine. It may + # be secondary repositories that we don't really care about. + [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update || /bin/true + NO_UPDATE_REPOS=True + + $xtrace + apt_get install "$@" + elif is_fedora; then + $xtrace + yum_install "$@" + elif is_suse; then + $xtrace + zypper_install "$@" + else + $xtrace + exit_distro_not_supported "installing packages" + fi +} + +# Distro-agnostic function to tell if a package is installed +# is_package_installed package [package ...] +function is_package_installed { + if [[ -z "$@" ]]; then + return 1 + fi + + if [[ -z "$os_PACKAGE" ]]; then + GetOSVersion + fi + + if [[ "$os_PACKAGE" = "deb" ]]; then + dpkg -s "$@" > /dev/null 2> /dev/null + elif [[ "$os_PACKAGE" = "rpm" ]]; then + rpm --quiet -q "$@" + else + exit_distro_not_supported "finding if a package is installed" + fi +} + +# Distro-agnostic package uninstaller +# uninstall_package package [package ...] +function uninstall_package { + if is_ubuntu; then + apt_get purge "$@" + elif is_fedora; then + sudo yum remove -y "$@" + elif is_suse; then + sudo zypper rm "$@" + else + exit_distro_not_supported "uninstalling packages" + fi +} + +# Wrapper for ``yum`` to set proxy environment variables +# Uses globals ``OFFLINE``, ``*_proxy`` +# yum_install package [package ...] +function yum_install { + [[ "$OFFLINE" = "True" ]] && return + local sudo="sudo" + [[ "$(id -u)" = "0" ]] && sudo="env" + + # The manual check for missing packages is because yum -y assumes + # missing packages are OK. See + # https://bugzilla.redhat.com/show_bug.cgi?id=965567 + $sudo http_proxy=$http_proxy https_proxy=$https_proxy \ + no_proxy=$no_proxy \ + yum install -y "$@" 2>&1 | \ + awk ' + BEGIN { fail=0 } + /No package/ { fail=1 } + { print } + END { exit fail }' || \ + die $LINENO "Missing packages detected" + + # also ensure we catch a yum failure + if [[ ${PIPESTATUS[0]} != 0 ]]; then + die $LINENO "Yum install failure" + fi +} + +# zypper wrapper to set arguments correctly +# zypper_install package [package ...] +function zypper_install { + [[ "$OFFLINE" = "True" ]] && return + local sudo="sudo" + [[ "$(id -u)" = "0" ]] && sudo="env" + $sudo http_proxy=$http_proxy https_proxy=$https_proxy \ + zypper --non-interactive install --auto-agree-with-licenses "$@" +} + + +# Process Functions +# ================= + +# _run_process() is designed to be backgrounded by run_process() to simulate a +# fork. It includes the dirty work of closing extra filehandles and preparing log +# files to produce the same logs as screen_it(). The log filename is derived +# from the service name and global-and-now-misnamed SCREEN_LOGDIR +# _run_process service "command-line" +function _run_process { + local service=$1 + local command="$2" + + # Undo logging redirections and close the extra descriptors + exec 1>&3 + exec 2>&3 + exec 3>&- + exec 6>&- + + if [[ -n ${SCREEN_LOGDIR} ]]; then + exec 1>&${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log 2>&1 + ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log + + # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs. + export PYTHONUNBUFFERED=1 + fi + + exec /bin/bash -c "$command" + die "$service exec failure: $command" +} + +# Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``. +# This is used for ``service_check`` when all the ``screen_it`` are called finished +# init_service_check +function init_service_check { + SCREEN_NAME=${SCREEN_NAME:-stack} + SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} + + if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then + mkdir -p "$SERVICE_DIR/$SCREEN_NAME" + fi + + rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure +} + +# Find out if a process exists by partial name. +# is_running name +function is_running { + local name=$1 + ps auxw | grep -v grep | grep ${name} > /dev/null + RC=$? + # some times I really hate bash reverse binary logic + return $RC +} + +# run_process() launches a child process that closes all file descriptors and +# then exec's the passed in command. This is meant to duplicate the semantics +# of screen_it() without screen. PIDs are written to +# $SERVICE_DIR/$SCREEN_NAME/$service.pid +# run_process service "command-line" +function run_process { + local service=$1 + local command="$2" + + # Spawn the child process + _run_process "$service" "$command" & + echo $! +} + +# Helper to launch a service in a named screen +# screen_it service "command-line" +function screen_it { + SCREEN_NAME=${SCREEN_NAME:-stack} + SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} + USE_SCREEN=$(trueorfalse True $USE_SCREEN) + + if is_service_enabled $1; then + # Append the service to the screen rc file + screen_rc "$1" "$2" + + if [[ "$USE_SCREEN" = "True" ]]; then + screen -S $SCREEN_NAME -X screen -t $1 + + if [[ -n ${SCREEN_LOGDIR} ]]; then + screen -S $SCREEN_NAME -p $1 -X logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log + screen -S $SCREEN_NAME -p $1 -X log on + ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log + fi + + # sleep to allow bash to be ready to be send the command - we are + # creating a new window in screen and then sends characters, so if + # bash isn't running by the time we send the command, nothing happens + sleep 1.5 + + NL=`echo -ne '\015'` + # This fun command does the following: + # - the passed server command is backgrounded + # - the pid of the background process is saved in the usual place + # - the server process is brought back to the foreground + # - if the server process exits prematurely the fg command errors + # and a message is written to stdout and the service failure file + # The pid saved can be used in screen_stop() as a process group + # id to kill off all child processes + screen -S $SCREEN_NAME -p $1 -X stuff "$2 & echo \$! >$SERVICE_DIR/$SCREEN_NAME/$1.pid; fg || echo \"$1 failed to start\" | tee \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL" + else + # Spawn directly without screen + run_process "$1" "$2" >$SERVICE_DIR/$SCREEN_NAME/$1.pid + fi + fi +} + +# Screen rc file builder +# screen_rc service "command-line" +function screen_rc { + SCREEN_NAME=${SCREEN_NAME:-stack} + SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc + if [[ ! -e $SCREENRC ]]; then + # Name the screen session + echo "sessionname $SCREEN_NAME" > $SCREENRC + # Set a reasonable statusbar + echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC + # Some distributions override PROMPT_COMMAND for the screen terminal type - turn that off + echo "setenv PROMPT_COMMAND /bin/true" >> $SCREENRC + echo "screen -t shell bash" >> $SCREENRC + fi + # If this service doesn't already exist in the screenrc file + if ! grep $1 $SCREENRC 2>&1 > /dev/null; then + NL=`echo -ne '\015'` + echo "screen -t $1 bash" >> $SCREENRC + echo "stuff \"$2$NL\"" >> $SCREENRC + + if [[ -n ${SCREEN_LOGDIR} ]]; then + echo "logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log" >>$SCREENRC + echo "log on" >>$SCREENRC + fi + fi +} + +# Stop a service in screen +# If a PID is available use it, kill the whole process group via TERM +# If screen is being used kill the screen window; this will catch processes +# that did not leave a PID behind +# screen_stop service +function screen_stop { + SCREEN_NAME=${SCREEN_NAME:-stack} + SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} + USE_SCREEN=$(trueorfalse True $USE_SCREEN) + + if is_service_enabled $1; then + # Kill via pid if we have one available + if [[ -r $SERVICE_DIR/$SCREEN_NAME/$1.pid ]]; then + pkill -TERM -P -$(cat $SERVICE_DIR/$SCREEN_NAME/$1.pid) + rm $SERVICE_DIR/$SCREEN_NAME/$1.pid + fi + if [[ "$USE_SCREEN" = "True" ]]; then + # Clean up the screen window + screen -S $SCREEN_NAME -p $1 -X kill + fi + fi +} + +# Helper to get the status of each running service +# service_check +function service_check { + local service + local failures + SCREEN_NAME=${SCREEN_NAME:-stack} + SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} + + + if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then + echo "No service status directory found" + return + fi + + # Check if there is any falure flag file under $SERVICE_DIR/$SCREEN_NAME + # make this -o errexit safe + failures=`ls "$SERVICE_DIR/$SCREEN_NAME"/*.failure 2>/dev/null || /bin/true` + + for service in $failures; do + service=`basename $service` + service=${service%.failure} + echo "Error: Service $service is not running" + done + + if [ -n "$failures" ]; then + die $LINENO "More details about the above errors can be found with screen, with ./rejoin-stack.sh" + fi +} + + +# Python Functions +# ================ + +# Get the path to the pip command. +# get_pip_command +function get_pip_command { + which pip || which pip-python + + if [ $? -ne 0 ]; then + die $LINENO "Unable to find pip; cannot continue" + fi +} + +# Get the path to the direcotry where python executables are installed. +# get_python_exec_prefix +function get_python_exec_prefix { + if is_fedora || is_suse; then + echo "/usr/bin" + else + echo "/usr/local/bin" + fi +} + +# Wrapper for ``pip install`` to set cache and proxy environment variables +# Uses globals ``OFFLINE``, ``PIP_DOWNLOAD_CACHE``, ``PIP_USE_MIRRORS``, +# ``TRACK_DEPENDS``, ``*_proxy`` +# pip_install package [package ...] +function pip_install { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + if [[ "$OFFLINE" = "True" || -z "$@" ]]; then + $xtrace + return + fi + + if [[ -z "$os_PACKAGE" ]]; then + GetOSVersion + fi + if [[ $TRACK_DEPENDS = True ]]; then + source $DEST/.venv/bin/activate + CMD_PIP=$DEST/.venv/bin/pip + SUDO_PIP="env" + else + SUDO_PIP="sudo" + CMD_PIP=$(get_pip_command) + fi + + # Mirror option not needed anymore because pypi has CDN available, + # but it's useful in certain circumstances + PIP_USE_MIRRORS=${PIP_USE_MIRRORS:-False} + if [[ "$PIP_USE_MIRRORS" != "False" ]]; then + PIP_MIRROR_OPT="--use-mirrors" + fi + + # pip < 1.4 has a bug where it will use an already existing build + # directory unconditionally. Say an earlier component installs + # foo v1.1; pip will have built foo's source in + # /tmp/$USER-pip-build. Even if a later component specifies foo < + # 1.1, the existing extracted build will be used and cause + # confusing errors. By creating unique build directories we avoid + # this problem. See https://github.com/pypa/pip/issues/709 + local pip_build_tmp=$(mktemp --tmpdir -d pip-build.XXXXX) + + $xtrace + $SUDO_PIP PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \ + http_proxy=$http_proxy \ + https_proxy=$https_proxy \ + no_proxy=$no_proxy \ + $CMD_PIP install --build=${pip_build_tmp} \ + $PIP_MIRROR_OPT $@ \ + && $SUDO_PIP rm -rf ${pip_build_tmp} +} + +# this should be used if you want to install globally, all libraries should +# use this, especially *oslo* ones +function setup_install { + local project_dir=$1 + setup_package_with_req_sync $project_dir +} + +# this should be used for projects which run services, like all services +function setup_develop { + local project_dir=$1 + setup_package_with_req_sync $project_dir -e +} + +# ``pip install -e`` the package, which processes the dependencies +# using pip before running `setup.py develop` +# +# Updates the dependencies in project_dir from the +# openstack/requirements global list before installing anything. +# +# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``, ``UNDO_REQUIREMENTS`` +# setup_develop directory +function setup_package_with_req_sync { + local project_dir=$1 + local flags=$2 + + # Don't update repo if local changes exist + # Don't use buggy "git diff --quiet" + # ``errexit`` requires us to trap the exit code when the repo is changed + local update_requirements=$(cd $project_dir && git diff --exit-code >/dev/null || echo "changed") + + if [[ $update_requirements != "changed" ]]; then + (cd $REQUIREMENTS_DIR; \ + $SUDO_CMD python update.py $project_dir) + fi + + setup_package $project_dir $flags + + # We've just gone and possibly modified the user's source tree in an + # automated way, which is considered bad form if it's a development + # tree because we've screwed up their next git checkin. So undo it. + # + # However... there are some circumstances, like running in the gate + # where we really really want the overridden version to stick. So provide + # a variable that tells us whether or not we should UNDO the requirements + # changes (this will be set to False in the OpenStack ci gate) + if [ $UNDO_REQUIREMENTS = "True" ]; then + if [[ $update_requirements != "changed" ]]; then + (cd $project_dir && git reset --hard) + fi + fi +} + +# ``pip install -e`` the package, which processes the dependencies +# using pip before running `setup.py develop` +# Uses globals ``STACK_USER`` +# setup_develop_no_requirements_update directory +function setup_package { + local project_dir=$1 + local flags=$2 + + pip_install $flags $project_dir + # ensure that further actions can do things like setup.py sdist + if [[ "$flags" == "-e" ]]; then + safe_chown -R $STACK_USER $1/*.egg-info + fi +} + + +# Service Functions +# ================= + +# remove extra commas from the input string (i.e. ``ENABLED_SERVICES``) +# _cleanup_service_list service-list +function _cleanup_service_list { + echo "$1" | sed -e ' + s/,,/,/g; + s/^,//; + s/,$// + ' +} + +# disable_all_services() removes all current services +# from ``ENABLED_SERVICES`` to reset the configuration +# before a minimal installation +# Uses global ``ENABLED_SERVICES`` +# disable_all_services +function disable_all_services { + ENABLED_SERVICES="" +} + +# Remove all services starting with '-'. For example, to install all default +# services except rabbit (rabbit) set in ``localrc``: +# ENABLED_SERVICES+=",-rabbit" +# Uses global ``ENABLED_SERVICES`` +# disable_negated_services +function disable_negated_services { + local tmpsvcs="${ENABLED_SERVICES}" + local service + for service in ${tmpsvcs//,/ }; do + if [[ ${service} == -* ]]; then + tmpsvcs=$(echo ${tmpsvcs}|sed -r "s/(,)?(-)?${service#-}(,)?/,/g") + fi + done + ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs") +} + +# disable_service() removes the services passed as argument to the +# ``ENABLED_SERVICES`` list, if they are present. +# +# For example: +# disable_service rabbit +# +# This function does not know about the special cases +# for nova, glance, and neutron built into is_service_enabled(). +# Uses global ``ENABLED_SERVICES`` +# disable_service service [service ...] +function disable_service { + local tmpsvcs=",${ENABLED_SERVICES}," + local service + for service in $@; do + if is_service_enabled $service; then + tmpsvcs=${tmpsvcs//,$service,/,} + fi + done + ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs") +} + +# enable_service() adds the services passed as argument to the +# ``ENABLED_SERVICES`` list, if they are not already present. +# +# For example: +# enable_service qpid +# +# This function does not know about the special cases +# for nova, glance, and neutron built into is_service_enabled(). +# Uses global ``ENABLED_SERVICES`` +# enable_service service [service ...] +function enable_service { + local tmpsvcs="${ENABLED_SERVICES}" + for service in $@; do + if ! is_service_enabled $service; then + tmpsvcs+=",$service" + fi + done + ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs") + disable_negated_services +} + +# is_service_enabled() checks if the service(s) specified as arguments are +# enabled by the user in ``ENABLED_SERVICES``. +# +# Multiple services specified as arguments are ``OR``'ed together; the test +# is a short-circuit boolean, i.e it returns on the first match. +# +# There are special cases for some 'catch-all' services:: +# **nova** returns true if any service enabled start with **n-** +# **cinder** returns true if any service enabled start with **c-** +# **ceilometer** returns true if any service enabled start with **ceilometer** +# **glance** returns true if any service enabled start with **g-** +# **neutron** returns true if any service enabled start with **q-** +# **swift** returns true if any service enabled start with **s-** +# **trove** returns true if any service enabled start with **tr-** +# For backward compatibility if we have **swift** in ENABLED_SERVICES all the +# **s-** services will be enabled. This will be deprecated in the future. +# +# Cells within nova is enabled if **n-cell** is in ``ENABLED_SERVICES``. +# We also need to make sure to treat **n-cell-region** and **n-cell-child** +# as enabled in this case. +# +# Uses global ``ENABLED_SERVICES`` +# is_service_enabled service [service ...] +function is_service_enabled { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local enabled=1 + services=$@ + for service in ${services}; do + [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && enabled=0 + + # Look for top-level 'enabled' function for this service + if type is_${service}_enabled >/dev/null 2>&1; then + # A function exists for this service, use it + is_${service}_enabled + enabled=$? + fi + + # TODO(dtroyer): Remove these legacy special-cases after the is_XXX_enabled() + # are implemented + + [[ ${service} == n-cell-* && ${ENABLED_SERVICES} =~ "n-cell" ]] && enabled=0 + [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && enabled=0 + [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && enabled=0 + [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && enabled=0 + [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && enabled=0 + [[ ${service} == "ironic" && ${ENABLED_SERVICES} =~ "ir-" ]] && enabled=0 + [[ ${service} == "neutron" && ${ENABLED_SERVICES} =~ "q-" ]] && enabled=0 + [[ ${service} == "trove" && ${ENABLED_SERVICES} =~ "tr-" ]] && enabled=0 + [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && enabled=0 + [[ ${service} == s-* && ${ENABLED_SERVICES} =~ "swift" ]] && enabled=0 + done + $xtrace + return $enabled +} + +# Toggle enable/disable_service for services that must run exclusive of each other +# $1 The name of a variable containing a space-separated list of services +# $2 The name of a variable in which to store the enabled service's name +# $3 The name of the service to enable +function use_exclusive_service { + local options=${!1} + local selection=$3 + out=$2 + [ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1 + for opt in $options;do + [[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt + done + eval "$out=$selection" + return 0 +} + + +# System Functions +# ================ + +# Only run the command if the target file (the last arg) is not on an +# NFS filesystem. +function _safe_permission_operation { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local args=( $@ ) + local last + local sudo_cmd + local dir_to_check + + let last="${#args[*]} - 1" + + dir_to_check=${args[$last]} + if [ ! -d "$dir_to_check" ]; then + dir_to_check=`dirname "$dir_to_check"` + fi + + if is_nfs_directory "$dir_to_check" ; then + $xtrace + return 0 + fi + + if [[ $TRACK_DEPENDS = True ]]; then + sudo_cmd="env" + else + sudo_cmd="sudo" + fi + + $xtrace + $sudo_cmd $@ +} + +# Exit 0 if address is in network or 1 if address is not in network +# ip-range is in CIDR notation: 1.2.3.4/20 +# address_in_net ip-address ip-range +function address_in_net { + local ip=$1 + local range=$2 + local masklen=${range#*/} + local network=$(maskip ${range%/*} $(cidr2netmask $masklen)) + local subnet=$(maskip $ip $(cidr2netmask $masklen)) + [[ $network == $subnet ]] +} + +# Add a user to a group. +# add_user_to_group user group +function add_user_to_group { + local user=$1 + local group=$2 + + if [[ -z "$os_VENDOR" ]]; then + GetOSVersion + fi + + # SLE11 and openSUSE 12.2 don't have the usual usermod + if ! is_suse || [[ "$os_VENDOR" = "openSUSE" && "$os_RELEASE" != "12.2" ]]; then + sudo usermod -a -G "$group" "$user" + else + sudo usermod -A "$group" "$user" + fi +} + +# Convert CIDR notation to a IPv4 netmask +# cidr2netmask cidr-bits +function cidr2netmask { + local maskpat="255 255 255 255" + local maskdgt="254 252 248 240 224 192 128" + set -- ${maskpat:0:$(( ($1 / 8) * 4 ))}${maskdgt:$(( (7 - ($1 % 8)) * 4 )):3} + echo ${1-0}.${2-0}.${3-0}.${4-0} +} + +# Gracefully cp only if source file/dir exists +# cp_it source destination +function cp_it { + if [ -e $1 ] || [ -d $1 ]; then + cp -pRL $1 $2 + fi +} + +# HTTP and HTTPS proxy servers are supported via the usual environment variables [1] +# ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in +# ``localrc`` or on the command line if necessary:: +# +# [1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html +# +# http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh + +function export_proxy_variables { + if [[ -n "$http_proxy" ]]; then + export http_proxy=$http_proxy + fi + if [[ -n "$https_proxy" ]]; then + export https_proxy=$https_proxy + fi + if [[ -n "$no_proxy" ]]; then + export no_proxy=$no_proxy + fi +} + +# Returns true if the directory is on a filesystem mounted via NFS. +function is_nfs_directory { + local mount_type=`stat -f -L -c %T $1` + test "$mount_type" == "nfs" +} + +# Return the network portion of the given IP address using netmask +# netmask is in the traditional dotted-quad format +# maskip ip-address netmask +function maskip { + local ip=$1 + local mask=$2 + local l="${ip%.*}"; local r="${ip#*.}"; local n="${mask%.*}"; local m="${mask#*.}" + local subnet=$((${ip%%.*}&${mask%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${ip##*.}&${mask##*.})) + echo $subnet +} + +# Service wrapper to restart services +# restart_service service-name +function restart_service { + if is_ubuntu; then + sudo /usr/sbin/service $1 restart + else + sudo /sbin/service $1 restart + fi +} + +# Only change permissions of a file or directory if it is not on an +# NFS filesystem. +function safe_chmod { + _safe_permission_operation chmod $@ +} + +# Only change ownership of a file or directory if it is not on an NFS +# filesystem. +function safe_chown { + _safe_permission_operation chown $@ +} + +# Service wrapper to start services +# start_service service-name +function start_service { + if is_ubuntu; then + sudo /usr/sbin/service $1 start + else + sudo /sbin/service $1 start + fi +} + +# Service wrapper to stop services +# stop_service service-name +function stop_service { + if is_ubuntu; then + sudo /usr/sbin/service $1 stop + else + sudo /sbin/service $1 stop + fi +} + + +# Restore xtrace +$XTRACE + +# Local variables: +# mode: shell-script +# End: diff --git a/labs/osbash/lib/functions.guest b/labs/osbash/lib/functions.guest new file mode 100644 index 00000000..953a5353 --- /dev/null +++ b/labs/osbash/lib/functions.guest @@ -0,0 +1,441 @@ +# This file contains bash functions that may be used by guest systems (VMs). + +# Sourcing this file calls functions fix_path_env and source_deploy. + +source "$LIB_DIR/functions.sh" +source "$LIB_DIR/functions-common-devstack" + +# Make devstack's operating system identification work with nounset +function init_os_ident { + if [[ -z "${os_PACKAGE:-""}" ]]; then + GetOSVersion + fi +} + +function source_deploy { + if [ -n "${VM_SHELL_USER:-}" ]; then + # Already sourced + return 0 + fi + if mountpoint -q /vagrant; then + source "$CONFIG_DIR/deploy.vagrant" + else + source "$CONFIG_DIR/deploy.osbash" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# If our sudo user's PATH is preserved (and does not contain sbin dirs), +# some commands won't be found. Observed with Vagrant shell provisioner +# scripts using sudo after "su - vagrant". +# Adding to the path seems preferable to messing with the vagrant user's +# sudoers environment (or working with a separate Vagrant user). + +function fix_path_env { + if is_root; then return 0; fi + if echo 'echo $PATH'|sudo sh|grep -q '/sbin'; then return 0; fi + export PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin +} +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +function zero_empty_space { + echo "Filling empty disk space with zeros" + sudo dd if=/dev/zero of=/filler bs=1M 2>/dev/null || true + sudo rm /filler +} +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# For guest scripts to let osbash know they are running; used when osbashauto +# runs scripts inside of the VM (STATUS_DIR directory must be shared between +# host and VM). + +function indicate_current_auto { + if [ "${VM_SHELL_USER:-}" = "osbash" ]; then + local scr_name=${1:-$(basename "$0")} + local fpath=${2:-"/$STATUS_DIR/$scr_name.begin"} + mkdir -p "$STATUS_DIR" + touch "$fpath" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Debug function to make a script halt execution until a tmp file is removed + +function wait_for_file { + # If no argument is passed, use empty string (to pass nounset option) + local msg=${1-""} + local wait_file=remove_to_continue + [ -n "$msg" ] && wait_file=${wait_file}_${msg} + touch "/tmp/$wait_file" + while [ -e "/tmp/$wait_file" ]; do + sleep 1 + done +} +#------------------------------------------------------------------------------- +# Copy stdin/stderr to log file +#------------------------------------------------------------------------------- + +function exec_logpath { + local log_path=$1 + + # Append all stdin and stderr to log file + exec > >(tee -a "$log_path") 2>&1 +} + +function exec_logfile { + local log_dir=${1:-/home/$VM_SHELL_USER/log} + + # Default extension is log + local ext=${2:-log} + + mkdir -p "$log_dir" + + # Log name based on name of running script + local base_name=$(basename "$0" .sh) + + local prefix=$(get_next_prefix "$log_dir" "$ext") + local log_name="${prefix}_$base_name.$ext" + + exec_logpath "$log_dir/$log_name" +} + +#------------------------------------------------------------------------------- +# Functions that need to run as root +#------------------------------------------------------------------------------- + +function as_root_fix_mount_vboxsf_link { + local file=/sbin/mount.vboxsf + if [ -L $file -a ! -e $file ]; then + echo "$file is a broken symlink. Trying to fix it." + shopt -s nullglob + local new=(/opt/VBoxGuestAdditions*/lib/VBoxGuestAdditions) + if [ -n "$new" ]; then + ln -sv "$new" /usr/lib/VBoxGuestAdditions + else + return 1 + fi + fi +} + +function as_root_inject_sudoer { + if grep -q "${VM_SHELL_USER}" /etc/sudoers; then + echo "${VM_SHELL_USER} already in /etc/sudoers" + else + echo "${VM_SHELL_USER} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + echo "Defaults:${VM_SHELL_USER} !requiretty" >> /etc/sudoers + fi +} + +# Change to a regular user to execute a guest script (and log its output) + +function as_root_exec_script { + local script_path=$1 + local script_name="$(basename "$script_path" .sh)" + + echo "$(date) start $script_path" + + local prefix=$(get_next_prefix "$LOG_DIR" "auto") + local log_path=$LOG_DIR/${prefix}_$script_name.auto + + su - "$VM_SHELL_USER" -c "bash $script_path" >"$log_path" 2>&1 + local rc=$? + if [ $rc -ne 0 ]; then + echo "$(date) ERROR: status $rc for $script_path" | + tee >&2 -a "$LOG_DIR/error.log" + else + echo "$(date) done" + fi + return $rc +} + +#------------------------------------------------------------------------------- +# Root wrapper around devstack function for manipulating config files +#------------------------------------------------------------------------------- + +function iniset_sudo { + local file=$1 + shift + local tmpfile=$(mktemp) + # Create a temporary copy, work on it, and copy it back into place + sudo cp -fv "$file" "$tmpfile" + iniset "$tmpfile" "$@" + cat "$tmpfile" | sudo tee "$file" >/dev/null +} + +#------------------------------------------------------------------------------- +# Functions for manipulating config files without section +#------------------------------------------------------------------------------- + +function iniset_sudo_no_section { + local file=$1 + shift + local tmpfile=$(mktemp) + # Create a temporary copy, work on it, and copy it back into place + sudo cp -fv "$file" "$tmpfile" + iniset_no_section "$tmpfile" "$@" + cat "$tmpfile" | sudo tee "$file" >/dev/null +} + +# ini_has_option_no_section config-file option +function ini_has_option_no_section { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local option=$2 + local line + line=$(sed -ne "/^$option[ \t]*=/ p;" "$file") + $xtrace + [ -n "$line" ] +} + +# Set an option in an INI file +# iniset_no_section config-file option value +function iniset_no_section { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local option=$2 + local value=$3 + + [[ -z $option ]] && return + + if ! ini_has_option_no_section "$file" "$option"; then + # Add it + sed -i -e "1 i\ +$option = $value +" "$file" + else + local sep=$(echo -ne "\x01") + # Replace it + sed -i -e "/$option/ c\ +$option = $value +" "$file" + fi + $xtrace +} + + +#------------------------------------------------------------------------------- +# OpenStack helpers +#------------------------------------------------------------------------------- + +function mysql_exe { + local cmd="$1" + echo "MySQL cmd: $cmd." + mysql -u "root" -p"$DATABASE_PASSWORD" -e "$cmd" +} + +function setup_database { + local service=$1 + local db_user=$(service_to_db_user $service) + local db_password=$(service_to_db_password $service) + mysql_exe "CREATE DATABASE $service" + mysql_exe "GRANT ALL ON ${service}.* TO '$db_user'@'%' IDENTIFIED BY '$db_password';" + mysql_exe "GRANT ALL ON ${service}.* TO '$db_user'@'localhost' IDENTIFIED BY '$db_password';" +} + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Users for service-specific MySQL databases + +function service_to_db_user { + local service_name=$1 + echo "${service_name}User" +} + +function service_to_db_password { + local service_name=$1 + echo "${service_name}Pass" +} + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Service-specific users in keystone + +function service_to_user_name { + local service_name=$1 + echo "${service_name}" +} + +function service_to_user_password { + local service_name=$1 + echo "${service_name}_pass" +} + +#------------------------------------------------------------------------------- +# Network configuration +#------------------------------------------------------------------------------- + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Fedora /etc/sysconfig/network-scripts/ifcfg-* configuration +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +function _ifnum_to_ifname_fedora { + local if_num=$1 + local -a if_names=('p2p1' 'p7p1' 'p8p1' 'p9p1') + + echo "${if_names[$if_num]}" +} + +function _config_sysconfig_nat { + local if_num=$1 + + local if_name="$(_ifnum_to_ifname_fedora "$if_num")" + + local if_file=/etc/sysconfig/network-scripts/ifcfg-$if_name + + sed -e " + s,%IF_NAME%,$if_name,g; + " "$TEMPLATE_DIR/template-fedora-ifcfg-nat" | sudo tee "$if_file" +} + +function _config_sysconfig_hostonly { + local if_num=$1 + local ip_address=$2 + + local if_name="$(_ifnum_to_ifname_fedora "$if_num")" + + local if_file=/etc/sysconfig/network-scripts/ifcfg-$if_name + + sed -e " + s,%IF_NAME%,$if_name,g; + s,%IP_ADDRESS%,$ip_address,g; + " "$TEMPLATE_DIR/template-fedora-ifcfg-hostonly" | sudo tee "$if_file" +} + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Ubuntu /etc/network/interfaces configuration +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +readonly UBUNTU_IF_FILE=/etc/network/interfaces + +function _ifnum_to_ifname_ubuntu { + local if_num=$1 + local -a if_names=('eth0' 'eth1' 'eth2' 'eth3') + + echo "${if_names[$if_num]}" +} + + +function _config_interfaces_nat { + local if_num=$1 + + local if_name="$(_ifnum_to_ifname_ubuntu "$if_num")" + + # Empty line before this entry + echo | sudo tee -a "$UBUNTU_IF_FILE" + + sed -e " + s,%IF_NAME%,$if_name,g; + " "$TEMPLATE_DIR/template-ubuntu-interfaces-nat" | sudo tee -a "$UBUNTU_IF_FILE" +} + +function _config_interfaces_hostonly { + local if_num=$1 + local ip_address=$2 + + local if_name="$(_ifnum_to_ifname_ubuntu "$if_num")" + + # Empty line before this entry + echo | sudo tee -a "$UBUNTU_IF_FILE" + + sed -e " + s,%IF_NAME%,$if_name,g; + s,%IP_ADDRESS%,$ip_address,g; + " "$TEMPLATE_DIR/template-ubuntu-interfaces-hostonly" | sudo tee -a "$UBUNTU_IF_FILE" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +function config_nat { + local if_num=$1 + + init_os_ident + if is_fedora; then + echo _config_sysconfig_nat "$if_num" + _config_sysconfig_nat "$if_num" + else + echo _config_interfaces_nat "$if_num" + _config_interfaces_nat "$if_num" + fi +} + +function config_hostonly { + local if_num=$1 + local ip_address=$2 + + init_os_ident + if is_fedora; then + echo _config_sysconfig_hostonly "$if_num" "$ip_address" + _config_sysconfig_hostonly "$if_num" "$ip_address" + else + echo _config_interfaces_hostonly "$if_num" "$ip_address" + _config_interfaces_hostonly "$if_num" "$ip_address" + fi +} + +function get_ip_from_net_and_fourth { + local net_name=$1 + local net="${!net_name}" + local fourth_octet=$2 + + echo "${net%.*}.$fourth_octet" +} + +function hostname_to_ip { + local host_name=$1 + getent hosts "$host_name"|awk '{print $1}' +} + +function config_network { + init_os_ident + if is_ubuntu; then + # Configuration functions will append to this file + sudo cp -v "$TEMPLATE_DIR/template-ubuntu-interfaces-loopback" \ + "$UBUNTU_IF_FILE" + fi + + # Get FOURTH_OCTET and network interfaces (NET_IF_?) for this node + unset -v NET_IF_0 NET_IF_1 NET_IF_2 NET_IF_3 + source "$CONFIG_DIR/config.$(hostname)" + + # Get API_NET, DATA_NET, MGMT_NET + source "$CONFIG_DIR/openstack" + + # Iterate over all NET_IF_? variables + local net_ifs=( "${!NET_IF_@}" ) + local net_if="" + for net_if in "${net_ifs[@]}"; do + echo >&2 -n "${net_if} ${!net_if}" + local if_num=${net_if##*_} + if [ "${!net_if}" = "nat" ]; then + echo >&2 + config_nat "$if_num" + else + # Host-only network: net_if is net name (e.g. API_NET) + # Use corresponding value (e.g. 192.168.100.1) + IP="$(get_ip_from_net_and_fourth "${!net_if}" "$FOURTH_OCTET")" + echo >&2 " $IP" + + config_hostonly "$if_num" "$IP" + fi + done +} + +#------------------------------------------------------------------------------- +# ssh wrapper functions +#------------------------------------------------------------------------------- + +function no_chk_ssh { + echo >&2 "ssh $@" + # Options set to disable strict host key checking and related messages. + ssh \ + -o "UserKnownHostsFile /dev/null" \ + -o "StrictHostKeyChecking no" \ + -o LogLevel=error \ + "$@" +} + +# ssh from one node VM to another node in the cluster +function node_ssh { + no_chk_ssh -i "$HOME/.ssh/osbash_key" "$@" +} + +#------------------------------------------------------------------------------- +fix_path_env +source_deploy +#------------------------------------------------------------------------------- + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/functions.sh b/labs/osbash/lib/functions.sh new file mode 100644 index 00000000..ba53562e --- /dev/null +++ b/labs/osbash/lib/functions.sh @@ -0,0 +1,91 @@ +# This file contains bash functions that may be used by both guest and host +# systems. + +# Non-recursive removal of all files except README.* +function clean_dir { + local target_dir=$1 + if [ ! -e "$target_dir" ]; then + mkdir -pv "$target_dir" + elif [ ! -d "$target_dir" ]; then + echo >&2 "Not a directory: $target_dir" + return 1 + fi + shopt -s nullglob + local entries=("$target_dir"/*) + if [ -n "${entries[0]-}" ]; then + for f in "${entries[@]}"; do + # Skip directories + if [ ! -f "$f" ]; then + continue + fi + + # Skip README.* + if [[ $f =~ /README\. ]]; then + continue + fi + + rm -f "$f" + done + fi +} + +function is_root { + if [ $EUID -eq 0 ]; then + return 0 + else + return 1 + fi +} + +function yes_or_no { + local prompt=$1 + local input="" + while [ : ]; do + read -p "$prompt (Y/n): " input + case "$input" in + N|n) + return 1 + ;; + ""|Y|y) + return 0 + ;; + *) + echo -e "${CError:-}Invalid input: ${CData:-}$input${CReset:-}" + ;; + esac + done +} + +#------------------------------------------------------------------------------- +# Helpers to incrementally number files via name prefixes +#------------------------------------------------------------------------------- + +function get_next_file_number { + local dir=$1 + local ext=${2:-""} + + # Get number of *.log files in directory + shopt -s nullglob + if [ -n "$ext" ]; then + # Count files with specific extension + local files=("$dir/"*".$ext") + else + # Count all files + local files=("$dir/"*) + fi + echo "${#files[*]}" +} + +function get_next_prefix { + local dir=$1 + local ext=$2 + # Number of digits in prefix string (default 3) + local digits=${3:-3} + + # Get number of *.$ext files in $dir + local cnt="$(get_next_file_number "$dir" "$ext")" + + printf "%0${digits}d" "$cnt" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash-ssh-keys/README.rst b/labs/osbash/lib/osbash-ssh-keys/README.rst new file mode 100644 index 00000000..7f2dbcfd --- /dev/null +++ b/labs/osbash/lib/osbash-ssh-keys/README.rst @@ -0,0 +1,2 @@ +This directory contains the insecure ssh keys used by osbash for logging into +the node VMs. diff --git a/labs/osbash/lib/osbash-ssh-keys/osbash_key b/labs/osbash/lib/osbash-ssh-keys/osbash_key new file mode 100644 index 00000000..26c6434e --- /dev/null +++ b/labs/osbash/lib/osbash-ssh-keys/osbash_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0pxig+FU4OyoaJjYRcYzvFX70h2Sc7hUr7YSvYyHh9vjOOUE +0eG2rWPuKjravQ8xoI7ElaeoT9kEn3FW2bUi9444d7I0jdxK0+FCnqkXoTV/2wip +nR4NHiuZtRGz6SZWPn80mI+Kg8OcfKw3haB1R8nYdo8kRXXd/fzHGjUDmLkEZmW0 +fX+yCEh/fYrCMZqLGJ9z3gHyFQHC6k/TnGD4DyifrbE72xZGBNoTokuxHpNAvdCj +lWyT9NVc92/3HBGEOVhZS9KKhZHrFUOSOHLYdcDBtuoJW2TuUlU9BgJXTML5vh/8 +J1YUPwIxeTZriBBp+OSuP3NHLKCM1nCnbjxMnwIDAQABAoIBAAkrH6rIE27bPpWX +GcsnzrbDM3w5J1f8TUt87KHtzTSf4OtoJOaSIea4c/TIrR8P20Q3Et3E97HKK8ZZ +I8PEe+o0+cZULq+CSIuiwciwacPt1UwOu3uIhF+s3DsisydSMOz1kq+ViB0mVdij +kqMxkgl3AwJeRuDzOZ/F8lD0v9xVFVggqA5DLJhrXtPXrkMZYDlI9RtA3qvD1/RN +/0QFiZNvbG9DpH/us5SWhI8FAtLgVBeylx5rLBebY59WGl2plyitGGOjtmTc7060 +bBWOZzT6PfruXvLj9O7dQwcEb0QNtAeNKHnyllYPNRHK8+WWP9JMg+h0JmV3r/UW +ArGUvAECgYEA9pBDiTPdHKEdJW/Aic4ZGWMNbkCbxN6tHNXPfUQrOiyWtpShUjzI +l4A9k6KTuWhsNQuLV2Cthdoa9WvEx9do/KXGuiXOhSkBm0ictsEeJMH50LbnQ6bX +qMx7EPdyxmKQjcblUkB2Q+0TovPTPI61U9KYRFsj4iDXDftlrf/+Jp8CgYEA2qve +2uWQvXWHe4EMKZpc/BqAIWmJiXzP9o4AD9ClOP9InNr2RVxVcTTVG0YEEqQDbPYi +lq5k65QAA7NaojvHaawhz+VPqRFAKtzqzUpsDZPh9Db737Qclh3WacQiEecmHwtP +1mYEIQTlCKTKfZ5yM0NASBD9kwWtjSSf2zpuGgECgYAEFfPojCF33fubqTRplC66 +SvfoAc4S/xWjSq+7hauptR9yOxhJQpSYXhmnHqSQB/jzEBPpCMMXWrvjoTuLjDhD +J4QZhZLchgduyU8/gAe92DEJkl5WsqcUNv87Er6mJu/6SXd3W3YaPg17P8saT8sV +boHzcAcyMhUeODJBJeLSRQKBgQDVOdygNFPz+oO20XoroyLijXC9o+yCTVt4PrUe +tsQ1lPCYSwbzUXrbXboj0x0rlBTnDgdiSQGNmY5+DUjmg0YK69c4opEP+gtJAIxQ +zC4a+0XMXkUyuK1bUBMApUjXjj7k7KHYHTgPfnda+12cKoGPLRekbjTlRRcbV0gt +fIdaAQKBgGE1nzOZtA0z1cEVcucfy9yHjZqic1JN0os1H52CzsPUwCjpAwTMct9J +7aLusbHBKQZgoOBuC0O/erV02oQIzTLWcjf45Uj52r0Rgt2kJpOKy8aPMZ9cpbq4 +tfMrBy/mZc7joHtfwtexLMm5EotkvHEzGXDIRZuyzOSTmlpSzEz3 +-----END RSA PRIVATE KEY----- diff --git a/labs/osbash/lib/osbash-ssh-keys/osbash_key.pub b/labs/osbash/lib/osbash-ssh-keys/osbash_key.pub new file mode 100644 index 00000000..e4c98a3d --- /dev/null +++ b/labs/osbash/lib/osbash-ssh-keys/osbash_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSnGKD4VTg7KhomNhFxjO8VfvSHZJzuFSvthK9jIeH2+M45QTR4batY+4qOtq9DzGgjsSVp6hP2QSfcVbZtSL3jjh3sjSN3ErT4UKeqRehNX/bCKmdHg0eK5m1EbPpJlY+fzSYj4qDw5x8rDeFoHVHydh2jyRFdd39/McaNQOYuQRmZbR9f7IISH99isIxmosYn3PeAfIVAcLqT9OcYPgPKJ+tsTvbFkYE2hOiS7Eek0C90KOVbJP01Vz3b/ccEYQ5WFlL0oqFkesVQ5I4cth1wMG26glbZO5SVT0GAldMwvm+H/wnVhQ/AjF5NmuIEGn45K4/c0csoIzWcKduPEyf osbash insecure public key diff --git a/labs/osbash/lib/osbash/functions-host.sh b/labs/osbash/lib/osbash/functions-host.sh new file mode 100644 index 00000000..784cad5e --- /dev/null +++ b/labs/osbash/lib/osbash/functions-host.sh @@ -0,0 +1,460 @@ +# This file contains bash functions that are used by osbash on the host. + +source "$LIB_DIR/functions.sh" + +#------------------------------------------------------------------------------- +# 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)" +} + +# From DISTRO string (e.g., ubuntu-14.04-server-amd64), get first component +function get_distro_name { + # Match up to first dash + local re='([^-]*)' + + if [[ $DISTRO =~ $re ]]; then + echo "${BASH_REMATCH[1]}" + fi +} + +#------------------------------------------------------------------------------- +# ssh +#------------------------------------------------------------------------------- + +# Check permission for osbash insecure private key +function check_osbash_private_key { + local key_name="osbash_key" + local osbash_key_dir=$LIB_DIR/osbash-ssh-keys + local osbash_key_path=$osbash_key_dir/$key_name + + if ! ls -l "$osbash_key_path"|grep -q "^-r--------"; then + echo "Adjusting permissions for $osbash_key_path" + chmod 400 "$osbash_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_osbash_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/osbash-ssh-keys/osbash_key" \ + -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_osbash_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/osbash-ssh-keys/osbash_key" \ + -o "UserKnownHostsFile /dev/null" \ + -o "StrictHostKeyChecking no" \ + -p "$ssh_port" \ + "$VM_SHELL_USER@localhost" "$@" +} + +function wait_for_ssh { + local ssh_port=$1 + + echo -e -n "${CStatus:-}Waiting for ssh server to respond on local port ${CData:-}$ssh_port.${CReset:-}" + 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 -e "${CError:-}ERROR: ssh returned status ${CData:-}$rc${CError:-} for${CData:-} $remote_path${CReset:-}" | + 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 { + # Run this function in sub-shell to protect our caller's environment + # (which might be _our_ enviroment if we get called again) + ( + + source "$CONFIG_DIR/config.$vm_name" + + local ssh_port=$VM_SSH_PORT + + 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 "${CError:-}\nERROR occured. Exiting.${CReset:-}" + 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 +# 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 [ ...] +# 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 -e >&2 "${CError:-}Error: bad option ${CData:-}$OPTARG.${CReset:-}" + 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 ] [-n ] + # 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_UI=$vm_ui _vbox_boot_with_autostart "$vm_name" + ;; + snapshot) + # Format: snapshot [-n ] + 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 ] + get_cmd_options $args + echo >&2 vm_wait_for_shutdown "$vm_name" + vm_wait_for_shutdown "$vm_name" + ;; + snapshot_cycle) + # Format: snapshot_cycle [-g ] [-n ] + # 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_wait_for_shutdown "$vm_name" + vm_snapshot "$vm_name" "$shot_name" + ;; + init_node) + # Format: init_node [-n ] + get_cmd_options $args + echo >&2 vm_init_node "$vm_name" + vm_init_node "$vm_name" + ;; + queue) + # Queue a script for autostart + # Format: queue + local script_rel_path=$args + echo >&2 _autostart_queue "$script_rel_path" + _autostart_queue "$script_rel_path" + ;; + *) + echo -e >&2 "${CError:-}Error: invalid cmd: ${CData:-}$cmd${CReset:-}" + 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 -e >&2 "${CMissing:-}Config file not found: ${CData:-}$config_file${CReset:-}" + 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 empty lines and lines that are commented out + continue + elif [ "$field_1" == "cmd" ]; then + if [ -n "${JUMP_SNAPSHOT:-""}" ]; then + if [[ $field_2 =~ ^snapshot.*${JUMP_SNAPSHOT} ]]; then + echo >&2 "Skipped forward to snapshot $JUMP_SNAPSHOT." + unset JUMP_SNAPSHOT + fi + else + command_from_config $field_2 + fi + else + # Syntax error + echo -e -n >&2 "${CError:-}ERROR in ${CInfo:-}$config_file: ${CData:-}'$field_1${CReset:-}" + if [ -n "$field_2" ]; then + echo >&2 " $field_2'" + else + echo >&2 "'" + fi + exit 1 + 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 -e >&2 "${CError:-}Unable to download ${CData:-}$url${CError:-}, quitting.${CReset:-}" + 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: diff --git a/labs/osbash/lib/osbash/lib-color.sh b/labs/osbash/lib/osbash/lib-color.sh new file mode 100644 index 00000000..d69a61c8 --- /dev/null +++ b/labs/osbash/lib/osbash/lib-color.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Colors and decorations + +function colorizer { + + # Text Reset + local Reset_Color='\x1b[0m' + + # Regular + local Black='\x1b[0;30m' + local Red='\x1b[0;31m' + local Green='\x1b[0;32m' + local Yellow='\x1b[0;33m' + local Blue='\x1b[0;34m' + local Purple='\x1b[0;35m' + local Cyan='\x1b[0;36m' + local White='\x1b[0;37m' + + # Bold + local Bold_Black='\x1b[1;30m' + local Bold_Red='\x1b[1;31m' + local Bold_Green='\x1b[1;32m' + local Bold_Yellow='\x1b[1;33m' + local Bold_Blue='\x1b[1;34m' + local Bold_Purple='\x1b[1;35m' + local Bold_Cyan='\x1b[1;36m' + local Bold_White='\x1b[1;37m' + + # Underline + local Underline_Black='\x1b[4;30m' + local Underline_Red='\x1b[4;31m' + local Underline_Green='\x1b[4;32m' + local Underline_Yellow='\x1b[4;33m' + local Underline_Blue='\x1b[4;34m' + local Underline_Purple='\x1b[1;35m' + local Underline_Cyan='\x1b[4;36m' + local Underline_White='\x1b[4;37m' + + # Background + local On_Black='\x1b[40m' + local On_Blue='\x1b[44m' + local On_White='\x1b[47m' + + # Color codes + CError=$Red + CStatus=$Bold_Purple + CInfo=$Bold_Yellow + CProcess=$Bold_Blue + CData=$Bold_Cyan + CMissing=$Bold_Red + CReset=$Reset_Color +} +colorizer +unset colorizer diff --git a/labs/osbash/lib/osbash/lib.fedora-20-x86_64 b/labs/osbash/lib/osbash/lib.fedora-20-x86_64 new file mode 100644 index 00000000..7a38ab24 --- /dev/null +++ b/labs/osbash/lib/osbash/lib.fedora-20-x86_64 @@ -0,0 +1,43 @@ +# Fedora 20 x86_64 + +# Default scripts for all Fedora base disks +: ${BASE_INSTALL_SCRIPTS:=scripts.fedora_base} + +# Give Fedora 20 installer sufficient RAM +VM_BASE_MEM=1024 + +#------------------------------------------------------------------------------- +# Booting the operating system installer +#------------------------------------------------------------------------------- + +readonly ISO_URL=http://mirror.switch.ch/ftp/mirror/fedora/linux/releases/20/Fedora/x86_64/iso/Fedora-20-x86_64-DVD.iso +readonly ISO_MD5=9a190c8b2bd382c2d046dbc855cd2f2b + +readonly _KS_ssh=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/ks-ssh-v2.cfg +readonly _KS_vbadd=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/ks-vbadd.cfg +readonly _KS_all=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/ks-all-v2.cfg + +readonly _BOOT_ARGS="linux ks=%s" + +function vbox_distro_start_installer { + local vm_name=$1 + + # pick a _KS_* file + local kickstart=_KS_$VM_ACCESS + + echo "Using $kickstart ${!kickstart}" + + local boot_args=$(printf "$_BOOT_ARGS" "${!kickstart}") + + vbox_kbd_escape_key "$vm_name" + + vbox_sleep 1 + + echo -e "${CStatus:-}Pushing boot command line${CReset:-}" + vbox_kbd_string_input "$vm_name" "$boot_args" + + echo "Initiating boot sequence" + vbox_kbd_enter_key "$vm_name" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash/lib.ubuntu-12.04.4-server-amd64 b/labs/osbash/lib/osbash/lib.ubuntu-12.04.4-server-amd64 new file mode 100644 index 00000000..e751dc3e --- /dev/null +++ b/labs/osbash/lib/osbash/lib.ubuntu-12.04.4-server-amd64 @@ -0,0 +1,53 @@ +# Ubuntu 12.04.4 LTS amd64 server + +# Default scripts for all Ubuntu installs +: ${BASE_INSTALL_SCRIPTS:=scripts.ubuntu_base} + +#------------------------------------------------------------------------------- +# Booting the operating system installer +#------------------------------------------------------------------------------- + +readonly ISO_URL=http://releases.ubuntu.com/12.04/ubuntu-12.04.4-server-amd64.iso + +# Note: Ubuntu 12.04 LTS cannot pull a preseed file over HTTPS +readonly _PS_ssh=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/preseed-ssh-v2.cfg +readonly _PS_vbadd=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/preseed-vbadd.cfg +readonly _PS_all=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/preseed-all-v2.cfg + +readonly _BOOT_ARGS="/install/vmlinuz + noapic + preseed/url=%s + debian-installer=en_US + auto=true + locale=en_US + hostname=osbash + fb=false + debconf/frontend=noninteractive + keyboard-configuration/modelcode=SKIP + initrd=/install/initrd.gz + console-setup/ask_detect=false" + +function vbox_distro_start_installer { + local vm_name=$1 + + # pick a _PS_* file + local preseed=_PS_$VM_ACCESS + + echo "Using $preseed ${!preseed}" + + local boot_args=$(printf "$_BOOT_ARGS" "${!preseed}") + + vbox_kbd_escape_key "$vm_name" + vbox_kbd_escape_key "$vm_name" + vbox_kbd_enter_key "$vm_name" + + vbox_sleep 1 + + echo -e "${CStatus:-}Pushing boot command line${CReset:-}" + vbox_kbd_string_input "$vm_name" "$boot_args" + + echo "Initiating boot sequence" + vbox_kbd_enter_key "$vm_name" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash/lib.ubuntu-14.04-server-amd64 b/labs/osbash/lib/osbash/lib.ubuntu-14.04-server-amd64 new file mode 100644 index 00000000..c06d57df --- /dev/null +++ b/labs/osbash/lib/osbash/lib.ubuntu-14.04-server-amd64 @@ -0,0 +1,53 @@ +# Ubuntu 14.04 LTS amd64 server + +# Default scripts for all Ubuntu installs +: ${BASE_INSTALL_SCRIPTS:=scripts.ubuntu_base} + +#------------------------------------------------------------------------------- +# Booting the operating system installer +#------------------------------------------------------------------------------- + +readonly ISO_URL=http://releases.ubuntu.com/14.04/ubuntu-14.04.3-server-amd64.iso +readonly ISO_MD5=9e5fecc94b3925bededed0fdca1bd417 + +readonly _PS_ssh=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/preseed-ssh-v2.cfg +readonly _PS_vbadd=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/preseed-vbadd.cfg +readonly _PS_all=http://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash/netboot/preseed-all-v2.cfg + +readonly _BOOT_ARGS="/install/vmlinuz + noapic + preseed/url=%s + debian-installer=en_US + auto=true + locale=en_US + hostname=osbash + fb=false + debconf/frontend=noninteractive + keyboard-configuration/modelcode=SKIP + initrd=/install/initrd.gz + console-setup/ask_detect=false" + +function vbox_distro_start_installer { + local vm_name=$1 + + # pick a _PS_* file + local preseed=_PS_$VM_ACCESS + + echo "Using $preseed ${!preseed}" + + local boot_args=$(printf "$_BOOT_ARGS" "${!preseed}") + + vbox_kbd_escape_key "$vm_name" + vbox_kbd_escape_key "$vm_name" + vbox_kbd_enter_key "$vm_name" + + vbox_sleep 1 + + echo -e "${CStatus:-}Pushing boot command line${CReset:-}" + vbox_kbd_string_input "$vm_name" "$boot_args" + + echo "Initiating boot sequence" + vbox_kbd_enter_key "$vm_name" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash/netboot/ks-all-v2.cfg b/labs/osbash/lib/osbash/netboot/ks-all-v2.cfg new file mode 100644 index 00000000..65283a12 --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/ks-all-v2.cfg @@ -0,0 +1,75 @@ +#platform=x86, AMD64, or Intel EM64T +#version=DEVEL +# Install OS instead of upgrade +install +# Keyboard layouts +keyboard 'us' +# Reboot after installation +reboot --eject +# Root password +rootpw --plaintext osbash +# User +user --name=osbash --password=osbash --plaintext +# System timezone +timezone Etc/UTC --isUtc +# System language +lang en_US +# Firewall configuration +firewall --disabled +# System authorization information +auth --useshadow --passalgo=sha512 +# Use CDROM installation media +cdrom +# Use text mode install +text +# SELinux configuration +selinux --permissive +# Do not configure the X Window System +skipx + +# System bootloader configuration +bootloader --location=mbr +# Partition clearing information +clearpart --all + +part /boot --fstype=ext4 --size=1024 +part pv.0 --grow --size=1 +volgroup ROOTDISK --pesize=4096 pv.0 +logvol swap --name=swap --vgname=ROOTDISK --recommended +logvol / --fstype=ext4 --name=root --vgname=ROOTDISK --size=1 --grow + +%pre --interpreter=bash +%end +#------------------------------------------------------------------------------- +# Enable ssh login with insecure osbash key and password-less sudo for osbash +# Install VirtualBox guest additions, bootstrap osbashauto +%post --interpreter=/bin/bash +DIR=/home/osbash/.ssh +mkdir $DIR +wget -O $DIR/authorized_keys https://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash-ssh-keys/osbash_key.pub +chmod 700 $DIR +chmod 400 $DIR/authorized_keys +chown -R osbash:osbash $DIR +echo "osbash ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "Defaults:osbash !requiretty" >> /etc/sudoers + +yum -y install dkms + +mount /dev/sr1 /mnt +/mnt/VBoxLinuxAdditions.run +umount /mnt + +echo -e '#!/bin/bash\nbash /media/sf_*/autostart/*activate_autostart.sh\nrm /media/*/autostart/*activate_autostart.sh' > /etc/init.d/osbash +chmod 755 /etc/init.d/osbash +ln -s ../init.d/osbash /etc/rc2.d/S40osbash +%end +#------------------------------------------------------------------------------- +# tar, bzip2, kernel-{devel,headers}: needed for VirtualBox guest additions +# (but not in @core) +%packages +wget +tar +bzip2 +kernel-devel +kernel-headers +%end diff --git a/labs/osbash/lib/osbash/netboot/ks-all.cfg b/labs/osbash/lib/osbash/netboot/ks-all.cfg new file mode 100644 index 00000000..76d9f80c --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/ks-all.cfg @@ -0,0 +1,75 @@ +#platform=x86, AMD64, or Intel EM64T +#version=DEVEL +# Install OS instead of upgrade +install +# Keyboard layouts +keyboard 'us' +# Reboot after installation +reboot --eject +# Root password +rootpw --plaintext osbash +# User +user --name=osbash --password=osbash --plaintext +# System timezone +timezone Etc/UTC --isUtc +# System language +lang en_US +# Firewall configuration +firewall --disabled +# System authorization information +auth --useshadow --passalgo=sha512 +# Use CDROM installation media +cdrom +# Use text mode install +text +# SELinux configuration +selinux --permissive +# Do not configure the X Window System +skipx + +# System bootloader configuration +bootloader --location=mbr +# Partition clearing information +clearpart --all + +part /boot --fstype=ext4 --size=1024 +part pv.0 --grow --size=1 +volgroup ROOTDISK --pesize=4096 pv.0 +logvol swap --name=swap --vgname=ROOTDISK --recommended +logvol / --fstype=ext4 --name=root --vgname=ROOTDISK --size=1 --grow + +%pre --interpreter=bash +%end +#------------------------------------------------------------------------------- +# Enable ssh login with insecure Vagrant key and password-less sudo for osbash +# Install VirtualBox guest additions, bootstrap osbashauto +%post --interpreter=/bin/bash +DIR=/home/osbash/.ssh +mkdir $DIR +wget -O $DIR/authorized_keys https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub +chmod 700 $DIR +chmod 400 $DIR/authorized_keys +chown -R osbash:osbash $DIR +echo "osbash ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "Defaults:osbash !requiretty" >> /etc/sudoers + +yum -y install dkms + +mount /dev/sr1 /mnt +/mnt/VBoxLinuxAdditions.run +umount /mnt + +echo -e '#!/bin/bash\nbash /media/sf_*/autostart/*activate_autostart.sh\nrm /media/*/autostart/*activate_autostart.sh' > /etc/init.d/osbash +chmod 755 /etc/init.d/osbash +ln -s ../init.d/osbash /etc/rc2.d/S40osbash +%end +#------------------------------------------------------------------------------- +# tar, bzip2, kernel-{devel,headers}: needed for VirtualBox guest additions +# (but not in @core) +%packages +wget +tar +bzip2 +kernel-devel +kernel-headers +%end diff --git a/labs/osbash/lib/osbash/netboot/ks-ssh-v2.cfg b/labs/osbash/lib/osbash/netboot/ks-ssh-v2.cfg new file mode 100644 index 00000000..fdd8cc22 --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/ks-ssh-v2.cfg @@ -0,0 +1,58 @@ +#platform=x86, AMD64, or Intel EM64T +#version=DEVEL +# Install OS instead of upgrade +install +# Keyboard layouts +keyboard 'us' +# Reboot after installation +reboot --eject +# Root password +rootpw --plaintext osbash +# User +user --name=osbash --password=osbash --plaintext +# System timezone +timezone Etc/UTC --isUtc +# System language +lang en_US +# Firewall configuration +firewall --disabled +# System authorization information +auth --useshadow --passalgo=sha512 +# Use CDROM installation media +cdrom +# Use text mode install +text +# SELinux configuration +selinux --permissive +# Do not configure the X Window System +skipx + +# System bootloader configuration +bootloader --location=mbr +# Partition clearing information +clearpart --all + +part /boot --fstype=ext4 --size=1024 +part pv.0 --grow --size=1 +volgroup ROOTDISK --pesize=4096 pv.0 +logvol swap --name=swap --vgname=ROOTDISK --recommended +logvol / --fstype=ext4 --name=root --vgname=ROOTDISK --size=1 --grow + +%pre --interpreter=bash +%end +#------------------------------------------------------------------------------- +# Enable ssh login with insecure osbash key and password-less sudo for osbash +%post --interpreter=/bin/bash +DIR=/home/osbash/.ssh +mkdir $DIR +wget -O $DIR/authorized_keys https://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash-ssh-keys/osbash_key.pub +chmod 700 $DIR +chmod 400 $DIR/authorized_keys +chown -R osbash:osbash $DIR +echo "osbash ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "Defaults:osbash !requiretty" >> /etc/sudoers +%end + +%packages +wget +%end diff --git a/labs/osbash/lib/osbash/netboot/ks-ssh.cfg b/labs/osbash/lib/osbash/netboot/ks-ssh.cfg new file mode 100644 index 00000000..45736a1f --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/ks-ssh.cfg @@ -0,0 +1,58 @@ +#platform=x86, AMD64, or Intel EM64T +#version=DEVEL +# Install OS instead of upgrade +install +# Keyboard layouts +keyboard 'us' +# Reboot after installation +reboot --eject +# Root password +rootpw --plaintext osbash +# User +user --name=osbash --password=osbash --plaintext +# System timezone +timezone Etc/UTC --isUtc +# System language +lang en_US +# Firewall configuration +firewall --disabled +# System authorization information +auth --useshadow --passalgo=sha512 +# Use CDROM installation media +cdrom +# Use text mode install +text +# SELinux configuration +selinux --permissive +# Do not configure the X Window System +skipx + +# System bootloader configuration +bootloader --location=mbr +# Partition clearing information +clearpart --all + +part /boot --fstype=ext4 --size=1024 +part pv.0 --grow --size=1 +volgroup ROOTDISK --pesize=4096 pv.0 +logvol swap --name=swap --vgname=ROOTDISK --recommended +logvol / --fstype=ext4 --name=root --vgname=ROOTDISK --size=1 --grow + +%pre --interpreter=bash +%end +#------------------------------------------------------------------------------- +# Enable ssh login with insecure Vagrant key and password-less sudo for osbash +%post --interpreter=/bin/bash +DIR=/home/osbash/.ssh +mkdir $DIR +wget -O $DIR/authorized_keys https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub +chmod 700 $DIR +chmod 400 $DIR/authorized_keys +chown -R osbash:osbash $DIR +echo "osbash ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "Defaults:osbash !requiretty" >> /etc/sudoers +%end + +%packages +wget +%end diff --git a/labs/osbash/lib/osbash/netboot/ks-vbadd.cfg b/labs/osbash/lib/osbash/netboot/ks-vbadd.cfg new file mode 100644 index 00000000..a133d6bf --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/ks-vbadd.cfg @@ -0,0 +1,64 @@ +#platform=x86, AMD64, or Intel EM64T +#version=DEVEL +# Install OS instead of upgrade +install +# Keyboard layouts +keyboard 'us' +# Reboot after installation +reboot --eject +# Root password +rootpw --plaintext osbash +# System timezone +timezone Etc/UTC --isUtc +# System language +lang en_US +# Firewall configuration +firewall --disabled +# System authorization information +auth --useshadow --passalgo=sha512 +# Use CDROM installation media +cdrom +# Use text mode install +text +# SELinux configuration +selinux --permissive +# Do not configure the X Window System +skipx + +# System bootloader configuration +bootloader --location=mbr +# Partition clearing information +clearpart --all + +part /boot --fstype=ext4 --size=1024 +part pv.0 --grow --size=1 +volgroup ROOTDISK --pesize=4096 pv.0 +logvol swap --name=swap --vgname=ROOTDISK --recommended +logvol / --fstype=ext4 --name=root --vgname=ROOTDISK --size=1 --grow + +%pre --interpreter=bash +%end +#------------------------------------------------------------------------------- +# Install VirtualBox guest additions, bootstrap osbashauto +%post --interpreter=/bin/bash + +yum -y install dkms + +mount /dev/sr1 /mnt +/mnt/VBoxLinuxAdditions.run +umount /mnt + +echo -e '#!/bin/bash\nbash /media/sf_*/autostart/*activate_autostart.sh\nrm /media/*/autostart/*activate_autostart.sh' > /etc/init.d/osbash +chmod 755 /etc/init.d/osbash +ln -s ../init.d/osbash /etc/rc2.d/S40osbash + +%end +#------------------------------------------------------------------------------- +# tar, bzip2, kernel-{devel,headers}: needed for VirtualBox guest additions +# (but not in @core) +%packages +tar +bzip2 +kernel-devel +kernel-headers +%end diff --git a/labs/osbash/lib/osbash/netboot/preseed-all-v2.cfg b/labs/osbash/lib/osbash/netboot/preseed-all-v2.cfg new file mode 100644 index 00000000..ed59a5d4 --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/preseed-all-v2.cfg @@ -0,0 +1,120 @@ +# Based on +# https://help.ubuntu.com/12.04/installation-guide/example-preseed.txt +# +# For details, see: +# https://help.ubuntu.com/12.04/installation-guide/i386/appendix-preseed.html +#------------------------------------------------------------------------------- +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Disable automatic (interactive) keymap detection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/layoutcode string us + +d-i netcfg/get_hostname string osbash +d-i netcfg/get_domain string unassigned-domain +#------------------------------------------------------------------------------- +# Proxy +#d-i mirror/http/proxy string http://192.168.178.20:3128/ +d-i mirror/http/proxy string +#------------------------------------------------------------------------------- +### Clock and time zone setup +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true +d-i time/zone string Etc/UTC +#------------------------------------------------------------------------------- +### Partitioning +# The presently available methods are: +# - regular: use the usual partition types for your architecture +# - lvm: use LVM to partition the disk +# - crypto: use LVM within an encrypted partition +d-i partman-auto/method string regular + +# You can choose one of the three predefined partitioning recipes: +# - atomic: all files in one partition +# - home: separate /home partition +# - multi: separate /home, /usr, /var, and /tmp partitions +d-i partman-auto/choose_recipe select atomic + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true +#------------------------------------------------------------------------------- +# To create a normal user account. +d-i passwd/user-fullname string OpenStack user +d-i passwd/username string osbash +d-i passwd/user-password password osbash +d-i passwd/user-password-again password osbash +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false +#------------------------------------------------------------------------------- +### Package selection +tasksel tasksel/first minimal + +# Individual additional packages to install +d-i pkgsel/include string openssh-server dkms localepurge + +# http://sfxpt.wordpress.com/2013/06/09/get-the-debianubuntu-ready-and-customized-the-way-you-like-in-10-minutes/ +### Pkg:localepurge +# Options explained at: http://anonscm.debian.org/cgit/collab-maint/localepurge.git/tree/debian/localepurge.templates +localepurge localepurge/nopurge multiselect en_US +# Really remove all locales? +localepurge localepurge/none_selected boolean false +# Also delete localized man pages? +localepurge localepurge/mandelete boolean true +# Avoid note that localepurge will not take any action until configured +localepurge localepurge/remove_no note +# Inform about new locales? +localepurge localepurge/dontbothernew boolean false +# Display verbose output? +localepurge localepurge/verbose boolean false +# Display freed disk space? +localepurge localepurge/showfreedspace boolean true +# Accurate disk space calculation? +localepurge localepurge/quickndirtycalc boolean true +# Use dpkg --path-exclude? +localepurge localepurge/use-dpkg-feature bolean true +#------------------------------------------------------------------------------- +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select none + +# Policy for applying updates. May be "none" (no automatic updates), +# "unattended-upgrades" (install security updates automatically), or +# "landscape" (manage system with Landscape). +d-i pkgsel/update-policy select none + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# Avoid warning about install CD not containing full support for language +d-i pkgsel/install-language-support boolean false + +# Avoid reboot confirmation +d-i finish-install/reboot_in_progress note + +d-i cdrom-detect/eject boolean true +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. + +# With Ubuntu 12.04 LTS, modesetting may result in a blank console +d-i debian-installer/add-kernel-opts string vga=0x301 nomodeset +#------------------------------------------------------------------------------- +#### Advanced options +### Running custom commands during the installation +# d-i preseeding is inherently not secure. Nothing in the installer checks +# for attempts at buffer overflows or other exploits of the values of a +# preconfiguration file like this one. Only use preconfiguration files from +# trusted locations! + +# This command is run just before the install finishes, but when there is +# still a usable /target directory. You can chroot to /target and use it +# directly, or use the apt-install and in-target commands to easily install +# packages and run commands in the target system. +d-i preseed/late_command string echo "DIR=/home/osbash/.ssh; mkdir \$DIR; wget -O \$DIR/authorized_keys https://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash-ssh-keys/osbash_key.pub ; chmod 700 \$DIR; chmod 400 \$DIR/authorized_keys; chown -R osbash:osbash \$DIR; echo 'osbash ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers; echo 'Defaults:osbash !requiretty' >> /etc/sudoers; apt-get -y purge virtualbox-guest-dkms virtualbox-guest-utils; mount /dev/sr1 /mnt; /mnt/VBoxLinuxAdditions.run; umount /mnt; echo -e '#!/bin/bash\nexec > /root/bootstrap.log 2>&1\nset -x\nSCR=/media/sf_bootstrap/autostart/*activate_autostart.sh\nwhile [ ! -f \$SCR ];do sleep 1;done\nbash \$SCR\nrm -v \$SCR' > /etc/rc2.d/S40osbash; chmod 755 /etc/rc2.d/S40osbash;" | chroot /target /bin/bash; diff --git a/labs/osbash/lib/osbash/netboot/preseed-all.cfg b/labs/osbash/lib/osbash/netboot/preseed-all.cfg new file mode 100644 index 00000000..1698dcf4 --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/preseed-all.cfg @@ -0,0 +1,120 @@ +# Based on +# https://help.ubuntu.com/12.04/installation-guide/example-preseed.txt +# +# For details, see: +# https://help.ubuntu.com/12.04/installation-guide/i386/appendix-preseed.html +#------------------------------------------------------------------------------- +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Disable automatic (interactive) keymap detection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/layoutcode string us + +d-i netcfg/get_hostname string osbash +d-i netcfg/get_domain string unassigned-domain +#------------------------------------------------------------------------------- +# Proxy +#d-i mirror/http/proxy string http://192.168.178.20:3128/ +d-i mirror/http/proxy string +#------------------------------------------------------------------------------- +### Clock and time zone setup +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true +d-i time/zone string Etc/UTC +#------------------------------------------------------------------------------- +### Partitioning +# The presently available methods are: +# - regular: use the usual partition types for your architecture +# - lvm: use LVM to partition the disk +# - crypto: use LVM within an encrypted partition +d-i partman-auto/method string regular + +# You can choose one of the three predefined partitioning recipes: +# - atomic: all files in one partition +# - home: separate /home partition +# - multi: separate /home, /usr, /var, and /tmp partitions +d-i partman-auto/choose_recipe select atomic + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true +#------------------------------------------------------------------------------- +# To create a normal user account. +d-i passwd/user-fullname string OpenStack user +d-i passwd/username string osbash +d-i passwd/user-password password osbash +d-i passwd/user-password-again password osbash +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false +#------------------------------------------------------------------------------- +### Package selection +tasksel tasksel/first minimal + +# Individual additional packages to install +d-i pkgsel/include string openssh-server dkms localepurge + +# http://sfxpt.wordpress.com/2013/06/09/get-the-debianubuntu-ready-and-customized-the-way-you-like-in-10-minutes/ +### Pkg:localepurge +# Options explained at: http://anonscm.debian.org/cgit/collab-maint/localepurge.git/tree/debian/localepurge.templates +localepurge localepurge/nopurge multiselect en_US +# Really remove all locales? +localepurge localepurge/none_selected boolean false +# Also delete localized man pages? +localepurge localepurge/mandelete boolean true +# Avoid note that localepurge will not take any action until configured +localepurge localepurge/remove_no note +# Inform about new locales? +localepurge localepurge/dontbothernew boolean false +# Display verbose output? +localepurge localepurge/verbose boolean false +# Display freed disk space? +localepurge localepurge/showfreedspace boolean true +# Accurate disk space calculation? +localepurge localepurge/quickndirtycalc boolean true +# Use dpkg --path-exclude? +localepurge localepurge/use-dpkg-feature bolean true +#------------------------------------------------------------------------------- +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select none + +# Policy for applying updates. May be "none" (no automatic updates), +# "unattended-upgrades" (install security updates automatically), or +# "landscape" (manage system with Landscape). +d-i pkgsel/update-policy select none + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# Avoid warning about install CD not containing full support for language +d-i pkgsel/install-language-support boolean false + +# Avoid reboot confirmation +d-i finish-install/reboot_in_progress note + +d-i cdrom-detect/eject boolean true +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. + +# With Ubuntu 12.04 LTS, modesetting may result in a blank console +d-i debian-installer/add-kernel-opts string vga=0x301 nomodeset +#------------------------------------------------------------------------------- +#### Advanced options +### Running custom commands during the installation +# d-i preseeding is inherently not secure. Nothing in the installer checks +# for attempts at buffer overflows or other exploits of the values of a +# preconfiguration file like this one. Only use preconfiguration files from +# trusted locations! + +# This command is run just before the install finishes, but when there is +# still a usable /target directory. You can chroot to /target and use it +# directly, or use the apt-install and in-target commands to easily install +# packages and run commands in the target system. +d-i preseed/late_command string echo "DIR=/home/osbash/.ssh; mkdir \$DIR; wget -O \$DIR/authorized_keys https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub ; chmod 700 \$DIR; chmod 400 \$DIR/authorized_keys; chown -R osbash:osbash \$DIR; echo 'osbash ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers; echo 'Defaults:osbash !requiretty' >> /etc/sudoers; apt-get -y purge virtualbox-guest-dkms virtualbox-guest-utils; mount /dev/sr1 /mnt; /mnt/VBoxLinuxAdditions.run; umount /mnt; echo -e '#!/bin/bash\nexec > /root/bootstrap.log 2>&1\nset -x\nSCR=/media/sf_bootstrap/autostart/*activate_autostart.sh\nwhile [ ! -f \$SCR ];do sleep 1;done\nbash \$SCR\nrm -v \$SCR' > /etc/rc2.d/S40osbash; chmod 755 /etc/rc2.d/S40osbash;" | chroot /target /bin/bash; diff --git a/labs/osbash/lib/osbash/netboot/preseed-ssh-v2.cfg b/labs/osbash/lib/osbash/netboot/preseed-ssh-v2.cfg new file mode 100644 index 00000000..558cd64c --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/preseed-ssh-v2.cfg @@ -0,0 +1,120 @@ +# Based on +# https://help.ubuntu.com/12.04/installation-guide/example-preseed.txt +# +# For details, see: +# https://help.ubuntu.com/12.04/installation-guide/i386/appendix-preseed.html +#------------------------------------------------------------------------------- +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Disable automatic (interactive) keymap detection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/layoutcode string us + +d-i netcfg/get_hostname string osbash +d-i netcfg/get_domain string unassigned-domain +#------------------------------------------------------------------------------- +# Proxy +#d-i mirror/http/proxy string http://192.168.178.20:3128/ +d-i mirror/http/proxy string +#------------------------------------------------------------------------------- +### Clock and time zone setup +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true +d-i time/zone string Etc/UTC +#------------------------------------------------------------------------------- +### Partitioning +# The presently available methods are: +# - regular: use the usual partition types for your architecture +# - lvm: use LVM to partition the disk +# - crypto: use LVM within an encrypted partition +d-i partman-auto/method string regular + +# You can choose one of the three predefined partitioning recipes: +# - atomic: all files in one partition +# - home: separate /home partition +# - multi: separate /home, /usr, /var, and /tmp partitions +d-i partman-auto/choose_recipe select atomic + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true +#------------------------------------------------------------------------------- +# To create a normal user account. +d-i passwd/user-fullname string OpenStack user +d-i passwd/username string osbash +d-i passwd/user-password password osbash +d-i passwd/user-password-again password osbash +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false +#------------------------------------------------------------------------------- +### Package selection +tasksel tasksel/first minimal + +# Individual additional packages to install +d-i pkgsel/include string openssh-server dkms localepurge + +# http://sfxpt.wordpress.com/2013/06/09/get-the-debianubuntu-ready-and-customized-the-way-you-like-in-10-minutes/ +### Pkg:localepurge +# Options explained at: http://anonscm.debian.org/cgit/collab-maint/localepurge.git/tree/debian/localepurge.templates +localepurge localepurge/nopurge multiselect en_US +# Really remove all locales? +localepurge localepurge/none_selected boolean false +# Also delete localized man pages? +localepurge localepurge/mandelete boolean true +# Avoid note that localepurge will not take any action until configured +localepurge localepurge/remove_no note +# Inform about new locales? +localepurge localepurge/dontbothernew boolean false +# Display verbose output? +localepurge localepurge/verbose boolean false +# Display freed disk space? +localepurge localepurge/showfreedspace boolean true +# Accurate disk space calculation? +localepurge localepurge/quickndirtycalc boolean true +# Use dpkg --path-exclude? +localepurge localepurge/use-dpkg-feature bolean true +#------------------------------------------------------------------------------- +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select none + +# Policy for applying updates. May be "none" (no automatic updates), +# "unattended-upgrades" (install security updates automatically), or +# "landscape" (manage system with Landscape). +d-i pkgsel/update-policy select none + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# Avoid warning about install CD not containing full support for language +d-i pkgsel/install-language-support boolean false + +# Avoid reboot confirmation +d-i finish-install/reboot_in_progress note + +d-i cdrom-detect/eject boolean true +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. + +# With Ubuntu 12.04 LTS, modesetting may result in a blank console +d-i debian-installer/add-kernel-opts string vga=0x301 nomodeset +#------------------------------------------------------------------------------- +#### Advanced options +### Running custom commands during the installation +# d-i preseeding is inherently not secure. Nothing in the installer checks +# for attempts at buffer overflows or other exploits of the values of a +# preconfiguration file like this one. Only use preconfiguration files from +# trusted locations! + +# This command is run just before the install finishes, but when there is +# still a usable /target directory. You can chroot to /target and use it +# directly, or use the apt-install and in-target commands to easily install +# packages and run commands in the target system. +d-i preseed/late_command string echo "DIR=/home/osbash/.ssh; mkdir \$DIR; wget -O \$DIR/authorized_keys https://git.openstack.org/cgit/openstack/training-guides/plain/labs/lib/osbash-ssh-keys/osbash_key.pub ; chmod 700 \$DIR; chmod 400 \$DIR/authorized_keys; chown -R osbash:osbash \$DIR; echo 'osbash ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers; echo 'Defaults:osbash !requiretty' >> /etc/sudoers;" | chroot /target /bin/bash; diff --git a/labs/osbash/lib/osbash/netboot/preseed-ssh.cfg b/labs/osbash/lib/osbash/netboot/preseed-ssh.cfg new file mode 100644 index 00000000..8bf76ee4 --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/preseed-ssh.cfg @@ -0,0 +1,120 @@ +# Based on +# https://help.ubuntu.com/12.04/installation-guide/example-preseed.txt +# +# For details, see: +# https://help.ubuntu.com/12.04/installation-guide/i386/appendix-preseed.html +#------------------------------------------------------------------------------- +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Disable automatic (interactive) keymap detection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/layoutcode string us + +d-i netcfg/get_hostname string osbash +d-i netcfg/get_domain string unassigned-domain +#------------------------------------------------------------------------------- +# Proxy +#d-i mirror/http/proxy string http://192.168.178.20:3128/ +d-i mirror/http/proxy string +#------------------------------------------------------------------------------- +### Clock and time zone setup +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true +d-i time/zone string Etc/UTC +#------------------------------------------------------------------------------- +### Partitioning +# The presently available methods are: +# - regular: use the usual partition types for your architecture +# - lvm: use LVM to partition the disk +# - crypto: use LVM within an encrypted partition +d-i partman-auto/method string regular + +# You can choose one of the three predefined partitioning recipes: +# - atomic: all files in one partition +# - home: separate /home partition +# - multi: separate /home, /usr, /var, and /tmp partitions +d-i partman-auto/choose_recipe select atomic + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true +#------------------------------------------------------------------------------- +# To create a normal user account. +d-i passwd/user-fullname string OpenStack user +d-i passwd/username string osbash +d-i passwd/user-password password osbash +d-i passwd/user-password-again password osbash +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false +#------------------------------------------------------------------------------- +### Package selection +tasksel tasksel/first minimal + +# Individual additional packages to install +d-i pkgsel/include string openssh-server dkms localepurge + +# http://sfxpt.wordpress.com/2013/06/09/get-the-debianubuntu-ready-and-customized-the-way-you-like-in-10-minutes/ +### Pkg:localepurge +# Options explained at: http://anonscm.debian.org/cgit/collab-maint/localepurge.git/tree/debian/localepurge.templates +localepurge localepurge/nopurge multiselect en_US +# Really remove all locales? +localepurge localepurge/none_selected boolean false +# Also delete localized man pages? +localepurge localepurge/mandelete boolean true +# Avoid note that localepurge will not take any action until configured +localepurge localepurge/remove_no note +# Inform about new locales? +localepurge localepurge/dontbothernew boolean false +# Display verbose output? +localepurge localepurge/verbose boolean false +# Display freed disk space? +localepurge localepurge/showfreedspace boolean true +# Accurate disk space calculation? +localepurge localepurge/quickndirtycalc boolean true +# Use dpkg --path-exclude? +localepurge localepurge/use-dpkg-feature bolean true +#------------------------------------------------------------------------------- +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select none + +# Policy for applying updates. May be "none" (no automatic updates), +# "unattended-upgrades" (install security updates automatically), or +# "landscape" (manage system with Landscape). +d-i pkgsel/update-policy select none + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# Avoid warning about install CD not containing full support for language +d-i pkgsel/install-language-support boolean false + +# Avoid reboot confirmation +d-i finish-install/reboot_in_progress note + +d-i cdrom-detect/eject boolean true +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. + +# With Ubuntu 12.04 LTS, modesetting may result in a blank console +d-i debian-installer/add-kernel-opts string vga=0x301 nomodeset +#------------------------------------------------------------------------------- +#### Advanced options +### Running custom commands during the installation +# d-i preseeding is inherently not secure. Nothing in the installer checks +# for attempts at buffer overflows or other exploits of the values of a +# preconfiguration file like this one. Only use preconfiguration files from +# trusted locations! + +# This command is run just before the install finishes, but when there is +# still a usable /target directory. You can chroot to /target and use it +# directly, or use the apt-install and in-target commands to easily install +# packages and run commands in the target system. +d-i preseed/late_command string echo "DIR=/home/osbash/.ssh; mkdir \$DIR; wget -O \$DIR/authorized_keys https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub ; chmod 700 \$DIR; chmod 400 \$DIR/authorized_keys; chown -R osbash:osbash \$DIR; echo 'osbash ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers; echo 'Defaults:osbash !requiretty' >> /etc/sudoers;" | chroot /target /bin/bash; diff --git a/labs/osbash/lib/osbash/netboot/preseed-vbadd.cfg b/labs/osbash/lib/osbash/netboot/preseed-vbadd.cfg new file mode 100644 index 00000000..56eab470 --- /dev/null +++ b/labs/osbash/lib/osbash/netboot/preseed-vbadd.cfg @@ -0,0 +1,120 @@ +# Based on +# https://help.ubuntu.com/12.04/installation-guide/example-preseed.txt +# +# For details, see: +# https://help.ubuntu.com/12.04/installation-guide/i386/appendix-preseed.html +#------------------------------------------------------------------------------- +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Disable automatic (interactive) keymap detection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/layoutcode string us + +d-i netcfg/get_hostname string osbash +d-i netcfg/get_domain string unassigned-domain +#------------------------------------------------------------------------------- +# Proxy +#d-i mirror/http/proxy string http://192.168.178.20:3128/ +d-i mirror/http/proxy string +#------------------------------------------------------------------------------- +### Clock and time zone setup +# Controls whether or not the hardware clock is set to UTC. +d-i clock-setup/utc boolean true +d-i time/zone string Etc/UTC +#------------------------------------------------------------------------------- +### Partitioning +# The presently available methods are: +# - regular: use the usual partition types for your architecture +# - lvm: use LVM to partition the disk +# - crypto: use LVM within an encrypted partition +d-i partman-auto/method string regular + +# You can choose one of the three predefined partitioning recipes: +# - atomic: all files in one partition +# - home: separate /home partition +# - multi: separate /home, /usr, /var, and /tmp partitions +d-i partman-auto/choose_recipe select atomic + +# This makes partman automatically partition without confirmation, provided +# that you told it what to do using one of the methods above. +d-i partman/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true +#------------------------------------------------------------------------------- +# To create a normal user account. +d-i passwd/user-fullname string OpenStack user +d-i passwd/username string osbash +d-i passwd/user-password password osbash +d-i passwd/user-password-again password osbash +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false +#------------------------------------------------------------------------------- +### Package selection +tasksel tasksel/first minimal + +# Individual additional packages to install +d-i pkgsel/include string openssh-server dkms localepurge + +# http://sfxpt.wordpress.com/2013/06/09/get-the-debianubuntu-ready-and-customized-the-way-you-like-in-10-minutes/ +### Pkg:localepurge +# Options explained at: http://anonscm.debian.org/cgit/collab-maint/localepurge.git/tree/debian/localepurge.templates +localepurge localepurge/nopurge multiselect en_US +# Really remove all locales? +localepurge localepurge/none_selected boolean false +# Also delete localized man pages? +localepurge localepurge/mandelete boolean true +# Avoid note that localepurge will not take any action until configured +localepurge localepurge/remove_no note +# Inform about new locales? +localepurge localepurge/dontbothernew boolean false +# Display verbose output? +localepurge localepurge/verbose boolean false +# Display freed disk space? +localepurge localepurge/showfreedspace boolean true +# Accurate disk space calculation? +localepurge localepurge/quickndirtycalc boolean true +# Use dpkg --path-exclude? +localepurge localepurge/use-dpkg-feature bolean true +#------------------------------------------------------------------------------- +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select none + +# Policy for applying updates. May be "none" (no automatic updates), +# "unattended-upgrades" (install security updates automatically), or +# "landscape" (manage system with Landscape). +d-i pkgsel/update-policy select none + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# Avoid warning about install CD not containing full support for language +d-i pkgsel/install-language-support boolean false + +# Avoid reboot confirmation +d-i finish-install/reboot_in_progress note + +d-i cdrom-detect/eject boolean true +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Use the following option to add additional boot parameters for the +# installed system (if supported by the bootloader installer). +# Note: options passed to the installer will be added automatically. + +# With Ubuntu 12.04 LTS, modesetting may result in a blank console +d-i debian-installer/add-kernel-opts string vga=0x301 nomodeset +#------------------------------------------------------------------------------- +#### Advanced options +### Running custom commands during the installation +# d-i preseeding is inherently not secure. Nothing in the installer checks +# for attempts at buffer overflows or other exploits of the values of a +# preconfiguration file like this one. Only use preconfiguration files from +# trusted locations! + +# This command is run just before the install finishes, but when there is +# still a usable /target directory. You can chroot to /target and use it +# directly, or use the apt-install and in-target commands to easily install +# packages and run commands in the target system. +d-i preseed/late_command string echo "apt-get -y purge virtualbox-guest-dkms virtualbox-guest-utils; mount /dev/sr1 /mnt; /mnt/VBoxLinuxAdditions.run; umount /mnt; echo -e '#!/bin/bash\nexec > /root/bootstrap.log 2>&1\nset -x\nSCR=/media/sf_bootstrap/autostart/*activate_autostart.sh\nwhile [ ! -f \$SCR ];do sleep 1;done\nbash \$SCR\nrm -v \$SCR' > /etc/rc2.d/S40osbash; chmod 755 /etc/rc2.d/S40osbash;" | chroot /target /bin/bash; diff --git a/labs/osbash/lib/osbash/scanlib.sh b/labs/osbash/lib/osbash/scanlib.sh new file mode 100644 index 00000000..f66c70f4 --- /dev/null +++ b/labs/osbash/lib/osbash/scanlib.sh @@ -0,0 +1,302 @@ +# The functions in this library are used to get scancode strings for VirtualBox +# keyboard input (keyboardputscancode). +# +# It was generated mostly from output of Cameron Kerr's scancodes.l: +# http://humbledown.org/keyboard-scancodes.xhtml +# +# The library works with bash 3.2 (shipped with Mac OS X as of 2014). + +function char2scancode { + local key=$1 + case "$key" in + 'a') + echo -n " 1e 9e" + ;; + 'b') + echo -n " 30 b0" + ;; + 'c') + echo -n " 2e ae" + ;; + 'd') + echo -n " 20 a0" + ;; + 'e') + echo -n " 12 92" + ;; + 'f') + echo -n " 21 a1" + ;; + 'g') + echo -n " 22 a2" + ;; + 'h') + echo -n " 23 a3" + ;; + 'i') + echo -n " 17 97" + ;; + 'j') + echo -n " 24 a4" + ;; + 'k') + echo -n " 25 a5" + ;; + 'l') + echo -n " 26 a6" + ;; + 'm') + echo -n " 32 b2" + ;; + 'n') + echo -n " 31 b1" + ;; + 'o') + echo -n " 18 98" + ;; + 'p') + echo -n " 19 99" + ;; + 'q') + echo -n " 10 90" + ;; + 'r') + echo -n " 13 93" + ;; + 's') + echo -n " 1f 9f" + ;; + 't') + echo -n " 14 94" + ;; + 'u') + echo -n " 16 96" + ;; + 'v') + echo -n " 2f af" + ;; + 'w') + echo -n " 11 91" + ;; + 'x') + echo -n " 2d ad" + ;; + 'y') + echo -n " 15 95" + ;; + 'z') + echo -n " 2c ac" + ;; + 'A') + echo -n " 2a 1e 9e aa" + ;; + 'B') + echo -n " 2a 30 b0 aa" + ;; + 'C') + echo -n " 2a 2e ae aa" + ;; + 'D') + echo -n " 2a 20 a0 aa" + ;; + 'E') + echo -n " 2a 12 92 aa" + ;; + 'F') + echo -n " 2a 21 a1 aa" + ;; + 'G') + echo -n " 2a 22 a2 aa" + ;; + 'H') + echo -n " 2a 23 a3 aa" + ;; + 'I') + echo -n " 2a 17 97 aa" + ;; + 'J') + echo -n " 2a 24 a4 aa" + ;; + 'K') + echo -n " 2a 25 a5 aa" + ;; + 'L') + echo -n " 2a 26 a6 aa" + ;; + 'M') + echo -n " 2a 32 b2 aa" + ;; + 'N') + echo -n " 2a 31 b1 aa" + ;; + 'O') + echo -n " 2a 18 98 aa" + ;; + 'P') + echo -n " 2a 19 99 aa" + ;; + 'Q') + echo -n " 2a 10 90 aa" + ;; + 'R') + echo -n " 2a 13 93 aa" + ;; + 'S') + echo -n " 2a 1f 9f aa" + ;; + 'T') + echo -n " 2a 14 94 aa" + ;; + 'U') + echo -n " 2a 16 96 aa" + ;; + 'V') + echo -n " 2a 2f af aa" + ;; + 'W') + echo -n " 2a 11 91 aa" + ;; + 'X') + echo -n " 2a 2d ad aa" + ;; + 'Z') + echo -n " 2a 2c ac aa" + ;; + 'Y') + echo -n " 2a 15 95 aa" + ;; + '1') + echo -n " 02 82" + ;; + '2') + echo -n " 03 83" + ;; + '3') + echo -n " 04 84" + ;; + '4') + echo -n " 05 85" + ;; + '5') + echo -n " 06 86" + ;; + '6') + echo -n " 07 87" + ;; + '7') + echo -n " 08 88" + ;; + '8') + echo -n " 09 89" + ;; + '9') + echo -n " 0a 8a" + ;; + '0') + echo -n " 0b 8b" + ;; + '!') + echo -n " 2a 02 82 aa" + ;; + '@') + echo -n " 2a 03 83 aa" + ;; + '#') + echo -n " 2a 04 84 aa" + ;; + '$') + echo -n " 2a 05 85 aa" + ;; + '%') + echo -n " 2a 06 86 aa" + ;; + '^') + echo -n " 2a 07 87 aa" + ;; + '&') + echo -n " 2a 08 88 aa" + ;; + '*') + echo -n " 2a 09 89 aa" + ;; + '(') + echo -n " 2a 0a 8a aa" + ;; + ')') + echo -n " 2a 0b 8b aa" + ;; + '-') + echo -n " 0c 8c" + ;; + '_') + echo -n " 2a 0c 8c aa" + ;; + '=') + echo -n " 0d 8d" + ;; + '+') + echo -n " 2a 0d 8d aa" + ;; + ' ') + echo -n " 39 b9" + ;; + '[') + echo -n " 1a 9a" + ;; + ']') + echo -n " 1b 9b" + ;; + '{') + echo -n " 2a 1a 9a aa" + ;; + '}') + echo -n " 2a 1b 9b aa" + ;; + ';') + echo -n " 27 a7" + ;; + ':') + echo -n " 2a 27 a7 aa" + ;; + ',') + echo -n " 33 b3" + ;; + '.') + echo -n " 34 b4" + ;; + '/') + echo -n " 35 b5" + ;; + '\') + echo -n " 2b ab" + ;; + '|') + echo -n " 2a 2b ab aa" + ;; + '?') + echo -n " 2a 35 b5 aa" + ;; + '"') + echo -n " 2a 28 a8 aa" + ;; + "'") + echo -n " 28 a8" + ;; + ">") + echo -n " 2a 34 b4 aa" + ;; + "<") + echo -n " 2a 33 b3 aa" + ;; + esac +} + +function esc2scancode { + echo -n " 01 81" +} + +function enter2scancode { + echo -n " 1c 9c" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash/templates/template-fedora-ifcfg-hostonly b/labs/osbash/lib/osbash/templates/template-fedora-ifcfg-hostonly new file mode 100644 index 00000000..0096a958 --- /dev/null +++ b/labs/osbash/lib/osbash/templates/template-fedora-ifcfg-hostonly @@ -0,0 +1,5 @@ +DEVICE=%IF_NAME% +ONBOOT=yes +BOOTPROTO=none +IPADDR=%IP_ADDRESS% +NETMASK=255.255.255.0 diff --git a/labs/osbash/lib/osbash/templates/template-fedora-ifcfg-nat b/labs/osbash/lib/osbash/templates/template-fedora-ifcfg-nat new file mode 100644 index 00000000..5b800ec8 --- /dev/null +++ b/labs/osbash/lib/osbash/templates/template-fedora-ifcfg-nat @@ -0,0 +1,4 @@ +# VirtualBox NAT -- for Internet access to VM +DEVICE=%IF_NAME% +ONBOOT=yes +BOOTPROTO=dhcp diff --git a/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-hostonly b/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-hostonly new file mode 100644 index 00000000..01c19476 --- /dev/null +++ b/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-hostonly @@ -0,0 +1,4 @@ +auto %IF_NAME% +iface %IF_NAME% inet static + address %IP_ADDRESS% + netmask 255.255.255.0 diff --git a/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-loopback b/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-loopback new file mode 100644 index 00000000..a6923a9d --- /dev/null +++ b/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-loopback @@ -0,0 +1,3 @@ +# The loopback network interface +auto lo +iface lo inet loopback diff --git a/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-nat b/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-nat new file mode 100644 index 00000000..bfc01382 --- /dev/null +++ b/labs/osbash/lib/osbash/templates/template-ubuntu-interfaces-nat @@ -0,0 +1,3 @@ +# VirtualBox NAT -- for Internet access to VM +auto eth0 +iface eth0 inet dhcp diff --git a/labs/osbash/lib/osbash/virtualbox-functions.sh b/labs/osbash/lib/osbash/virtualbox-functions.sh new file mode 100644 index 00000000..5e4beccb --- /dev/null +++ b/labs/osbash/lib/osbash/virtualbox-functions.sh @@ -0,0 +1,738 @@ +#------------------------------------------------------------------------------- +# VirtualBoxManage +#------------------------------------------------------------------------------- + +VBM=vbm +: ${VBM_LOG:=$LOG_DIR/vbm.log} + +# vbm is a wrapper around the VirtualBox VBoxManage executable; it handles +# logging and conditional execution (set OSBASH= to prevent the actual call to +# VBoxManage, or WBATCH= to keep a call from being recorded for Windows batch +# files) +function vbm { + ${WBATCH:-:} wbatch_log_vbm "$@" + + mkdir -p "$(dirname "$VBM_LOG")" + + if [[ -n "${OSBASH:-}" ]]; then + echo "$@" >> "$VBM_LOG" + local rc=0 + "$VBM_EXE" "$@" || rc=$? + if [ $rc -ne 0 ]; then + echo -e >&2 "${CError:-}FAILURE: VBoxManage: $@${CReset:-}" + return 1 + fi + else + echo "(not executed) $@" >> "$VBM_LOG" + fi +} + +# Return VirtualBox version string (without distro extensions) +function get_vb_version { + local version="" + # e.g. 4.1.32r92798 4.3.10_RPMFusionr93012 4.3.10_Debianr93012 + local raw=$(WBATCH= $VBM --version) + # Sanitize version string + local re='([0-9]+\.[0-9]+\.[0-9]+).*' + if [[ $raw =~ $re ]]; then + version=${BASH_REMATCH[1]} + fi + echo "$version" +} + +#------------------------------------------------------------------------------- +# VM status +#------------------------------------------------------------------------------- + +function vm_exists { + local vm_name=$1 + return $(WBATCH= $VBM list vms | grep -q "\"$vm_name\"") +} + +function vm_is_running { + local vm_name=$1 + return $(WBATCH= $VBM showvminfo --machinereadable "$vm_name" | \ + grep -q 'VMState="running"') +} + +function vm_wait_for_shutdown { + local vm_name=$1 + + ${WBATCH:-:} wbatch_wait_poweroff "$vm_name" + # Return if we are just faking it for wbatch + ${OSBASH:+:} return 0 + + echo -e >&2 -n "${CStatus:-}Machine shutting down${CReset:-}" + until WBATCH= $VBM showvminfo --machinereadable "$vm_name" 2>/dev/null | \ + grep -q '="poweroff"'; do + echo -n . + sleep 1 + done + echo >&2 -e "${CStatus:-}\nMachine powered off.${CReset:-}" +} + +function vm_power_off { + local vm_name=$1 + if vm_is_running "$vm_name"; then + echo -e >&2 "${CStatus:-}Powering off VM ${CData:-}\"$vm_name\"${CReset:-}" + $VBM controlvm "$vm_name" poweroff + fi + # VirtualBox VM needs a break before taking new commands + vbox_sleep 1 +} + +function vm_snapshot { + local vm_name=$1 + local shot_name=$2 + + $VBM snapshot "$vm_name" take "$shot_name" + # VirtualBox VM needs a break before taking new commands + vbox_sleep 1 +} + +#------------------------------------------------------------------------------- +# Host-only network functions +#------------------------------------------------------------------------------- + +function hostonlyif_in_use { + local if_name=$1 + return $(WBATCH= $VBM list -l runningvms | \ + grep -q "Host-only Interface '$if_name'") +} + +function ip_to_hostonlyif { + local ip=$1 + local prevline="" + WBATCH= $VBM list hostonlyifs | grep -e "^Name:" -e "^IPAddress:" | \ + while read line; do + if [[ "$line" == *$ip* ]]; then + # match longest string that ends with a space + echo ${prevline##Name:* } + break + fi + prevline=$line + done +} + +function create_hostonlyif { + local out=$(WBATCH= $VBM hostonlyif create 2> /dev/null | grep "^Interface") + # out is something like "Interface 'vboxnet3' was successfully created" + local re="Interface '(.*)' was successfully created" + if [[ $out =~ $re ]]; then + echo "${BASH_REMATCH[1]}" + else + echo -e >&2 "${CError:-}Host-only interface creation failed${CReset:-}" + return 1 + fi +} + +function create_network { + local ip=$1 + + # If we are here only for wbatch, ignore actual network interfaces; just + # return a unique identifier (so it can be replaced with the interface + # name used by Windows). + ${OSBASH:+:} mktemp -u XXXXXXXX + ${OSBASH:+:} return 0 + + local if_name="$(ip_to_hostonlyif "$ip")" + if [ -n "$if_name" ]; then + if hostonlyif_in_use "$if_name"; then + echo >&2 "Host-only interface $if_name ($ip) is in use." \ + "Using it, too." + fi + else + echo -e >&2 "${CStatus:-}Creating host-only interface${CReset:-}" + if_name=$(create_hostonlyif) + fi + + echo -e >&2 "${CStatus:-}Configuring host-only network ${CData:-}$ip ($if_name)${CReset:-}" + $VBM hostonlyif ipconfig "$if_name" \ + --ip "$ip" \ + --netmask 255.255.255.0 >/dev/null + echo "$if_name" +} + +#------------------------------------------------------------------------------- +# Disk functions +#------------------------------------------------------------------------------- + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Creating, registering and unregistering disk images with VirtualBox +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# disk can be either a path or a disk UUID +function disk_registered { + local disk=$1 + return $(WBATCH= $VBM list hdds | grep -q "$disk") +} + +# disk can be either a path or a disk UUID +function disk_unregister { + local disk=$1 + echo >&2 -e "${CStatus:-}Unregistering disk\n\t${CData:-}$disk${CReset:-}" + $VBM closemedium disk "$disk" +} + +function create_vdi { + local hd_path=$1 + local size=$2 + echo >&2 -e "${CStatus:-}Creating disk:\n\t${CData:-}$hd_path${CReset:-}" + $VBM createhd --format VDI --filename "$hd_path" --size "$size" +} + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Attaching and detaching disks from VMs +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# disk can be either a path or a disk UUID +function get_next_child_uuid { + local disk=$1 + local child_uuid="" + local line="" + if disk_registered "$disk"; then + line=$(WBATCH= $VBM showhdinfo "$disk" | grep -e "^Child UUIDs:") + child_uuid=${line##Child UUIDs:* } + fi + echo -e "next_child_uuid $disk:\n\t$line\n\t$child_uuid" >> "$VBM_LOG" + echo "$child_uuid" +} + +# disk can be either a path or a disk UUID +function path_to_disk_uuid { + local disk=$1 + local uuid="" + local line=$(WBATCH= $VBM showhdinfo "$disk" | grep -e "^UUID:") + local re='UUID:[ ]+([^ ]+)' + if [[ $line =~ $re ]]; then + uuid=${BASH_REMATCH[1]} + fi + echo -e "path_to_disk_uuid $disk:\n\t$line\n\t$uuid" >> "$VBM_LOG" + echo "$uuid" +} + +# disk can be either a path or a disk UUID +function disk_to_path { + local disk=$1 + local fpath="" + local line=$(WBATCH= $VBM showhdinfo "$disk" | grep -e "^Location:") + local re='Location:[ ]+([^ ]+)' + if [[ $line =~ $re ]]; then + fpath=${BASH_REMATCH[1]} + fi + echo -e "disk_to_path $disk:\n\t$line\n\t$fpath" >> "$VBM_LOG" + echo "$fpath" +} + +# disk can be either a path or a disk UUID +function disk_to_vm { + local disk=$1 + local vm_name="" + local line=$(WBATCH= $VBM showhdinfo "$disk" | grep -e "^In use by VMs:") + local re='In use by VMs:[ ]+([^ ]+) ' + if [[ $line =~ $re ]]; then + vm_name=${BASH_REMATCH[1]} + fi + echo -e "disk_to_vm $disk:\n\t$line\n\t$vm_name" >> "$VBM_LOG" + echo "$vm_name" +} + +function vm_get_disk_path { + local vm_name=$1 + local line=$(WBATCH= $VBM showvminfo --machinereadable "$vm_name" | \ + grep '^"SATA-0-0"=.*vdi"$') + local hd_path=${line##\"SATA-0-0\"=\"} + hd_path=${hd_path%\"} + echo "$hd_path" +} + +function vm_detach_disk { + local vm_name=$1 + echo >&2 "Detaching disk from VM \"$vm_name\"" + $VBM storageattach "$vm_name" \ + --storagectl SATA \ + --port 0 \ + --device 0 \ + --type hdd \ + --medium none + # VirtualBox VM needs a break before taking new commands + vbox_sleep 1 +} + +# disk can be either a path or a disk UUID +function vm_attach_disk { + local vm_name=$1 + local disk=$2 + echo >&2 -e "Attaching to VM \"$vm_name\":\n\t$disk" + $VBM storageattach "$vm_name" \ + --storagectl SATA \ + --port 0 \ + --device 0 \ + --type hdd \ + --medium "$disk" +} + +# disk can be either a path or a disk UUID +function vm_attach_disk_multi { + local vm_name=$1 + local disk=$2 + + $VBM modifyhd --type multiattach "$disk" + + echo >&2 -e "Attaching to VM \"$vm_name\":\n\t$disk" + $VBM storageattach "$vm_name" \ + --storagectl SATA \ + --port 0 \ + --device 0 \ + --type hdd \ + --medium "$disk" +} + +#------------------------------------------------------------------------------- +# VM create and configure +#------------------------------------------------------------------------------- + +function vm_mem { + local vm_name="$1" + local mem="$2" + $VBM modifyvm "$vm_name" --memory "$mem" +} + +function vm_cpus { + local vm_name="$1" + local cpus="$2" + $VBM modifyvm "$vm_name" --cpus "$cpus" +} + +# Port forwarding from host to VM (binding to host's 127.0.0.1) +function vm_port { + local vm_name="$1" + local desc="$2" + local hostport="$3" + local guestport="$4" + $VBM modifyvm "$vm_name" \ + --natpf1 "$desc,tcp,127.0.0.1,$hostport,,$guestport" +} + +function vm_nic_hostonly { + local vm_name=$1 + # We start counting interfaces at 0, but VirtualBox starts NICs at 1 + local nic=$(($2 + 1)) + local net_name=$3 + $VBM modifyvm "$vm_name" \ + "--nictype$nic" "$NICTYPE" \ + "--nic$nic" hostonly \ + "--hostonlyadapter$nic" "$net_name" \ + "--nicpromisc$nic" allow-all +} + +function vm_nic_nat { + local vm_name=$1 + # We start counting interfaces at 0, but VirtualBox starts NICs at 1 + local nic=$(($2 + 1)) + $VBM modifyvm "$vm_name" "--nictype$nic" "$NICTYPE" "--nic$nic" nat +} + +function vm_create { + # NOTE: We assume that a VM with a matching name is ours. + # Remove and recreate just in case someone messed with it. + local vm_name=$1 + + ${WBATCH:-:} wbatch_abort_if_vm_exists "$vm_name" + + # Don't write to wbatch scripts, and don't execute when we are faking it + # it for wbatch + WBATCH= ${OSBASH:-:} vm_delete "$vm_name" + + # XXX ostype is distro-specific; moving it to modifyvm disables networking + + # Note: The VirtualBox GUI may not notice group changes after VM creation + # until GUI is restarted. Moving a VM with group membership will + # fail in cases (lingering files from old VM) where creating a + # VM in that location succeeds. + # + # XXX temporary hack + # --groups not supported in VirtualBox 4.1 (Mac OS X 10.5) + echo -e >&2 "${CStatus:-}Creating VM ${CData:-}\"$vm_name\"${CReset:-}" + local ver=$(get_vb_version) + if [[ $ver = 4.1* ]]; then + $VBM createvm \ + --name "$vm_name" \ + --register \ + --ostype Ubuntu_64 >/dev/null + else + $VBM createvm \ + --name "$vm_name" \ + --register \ + --ostype Ubuntu_64 \ + --groups "/$VM_GROUP" >/dev/null + fi + + $VBM modifyvm "$vm_name" --rtcuseutc on + $VBM modifyvm "$vm_name" --biosbootmenu disabled + $VBM modifyvm "$vm_name" --largepages on + $VBM modifyvm "$vm_name" --boot1 disk + + # XXX temporary hack + # --portcount not supported in VirtualBox 4.1 (Mac OS X 10.5) + if [[ $ver == 4.1* ]]; then + $VBM storagectl "$vm_name" --name SATA --add sata + else + $VBM storagectl "$vm_name" --name SATA --add sata --portcount 1 + fi + $VBM storagectl "$vm_name" --name SATA --hostiocache on + + $VBM storagectl "$vm_name" --name IDE --add ide + echo -e >&2 "${CStatus:-}Created VM ${CData:-}\"$vm_name\"${CReset:-}" +} + +#------------------------------------------------------------------------------- +# VM export +#------------------------------------------------------------------------------- + +# Export node VMs to OVA package file +function vm_export_ova { + local ova_file=$1 + local nodes=$2 + echo >&2 "Removing shared folders for export" + local -a share_paths + local node + for node in $nodes; do + local share_path=$(vm_get_share_path "$node") + share_paths+=("$share_path") + if [ -n "$share_path" ]; then + vm_rm_share "$node" "$SHARE_NAME" + fi + done + rm -f "$ova_file" + mkdir -pv "$IMG_DIR" + $VBM export $nodes --output "$ova_file" + echo >&2 "Appliance exported" + echo >&2 "Reattaching shared folders" + local ii=0 + for node in $nodes; do + if [ -n "${share_paths[$ii]}" ]; then + vm_add_share "$node" "${share_paths[$ii]}" "$SHARE_NAME" + fi + ii=$(($ii + 1)) + done +} + +# Export node VMs by cloning VMs to directory +function vm_export_dir { + local export_dir=$1 + local nodes=$2 + + rm -rvf "$export_dir" + + for node in $nodes; do + if vm_is_running "$node"; then + echo "Powering off node VM $node." + echo "$VBM controlvm $node poweroff" + $VBM controlvm "$node" poweroff + fi + sleep 1 + local share_path=$(vm_get_share_path "$node") + if [ -n "$share_path" ]; then + echo >&2 "Removing shared folder for export" + vm_rm_share "$node" "$SHARE_NAME" + fi + sleep 1 + echo "Exporting VM $node to $export_dir" + # Use all: machineandchildren works only if --snapshot is given as UUID + $VBM clonevm "$node" \ + --mode all \ + --options keepallmacs,keepdisknames \ + --name "$node-e" \ + --groups "/$VM_GROUP" \ + --basefolder "$export_dir" \ + --register + # VirtualBox registers disks and snapshots of the clone VM even if we + # don't register the VM above. Unregistering the registered VM takes + # care of the snapshots, but we still have to unregister the clone + # basedisk. + local snapshot_path="$(vm_get_disk_path "$node-e")" + local hd_dir=${snapshot_path%Snapshots/*} + local hd_path=$hd_dir$(get_base_disk_name) + $VBM unregistervm "$node-e" + if [ -n "$hd_path" ]; then + disk_unregister "$hd_path" + fi + if [ -n "$share_path" ]; then + echo >&2 "Reattaching shared folder" + vm_add_share "$node" "$share_path" "$SHARE_NAME" + fi + done +} + +#------------------------------------------------------------------------------- +# VM unregister, remove, delete +#------------------------------------------------------------------------------- + +function vm_unregister_del { + local vm_name=$1 + echo -e >&2 "${CStatus:-}Unregistering and deleting VM ${CData:-}\"$vm_name\"${CReset:-}" + $VBM unregistervm "$vm_name" --delete +} + +function vm_delete { + local vm_name=$1 + echo >&2 -n "Asked to delete VM \"$vm_name\" " + if vm_exists "$vm_name"; then + echo >&2 "(found)" + vm_power_off "$vm_name" + local hd_path="$(vm_get_disk_path "$vm_name")" + if [ -n "$hd_path" ]; then + echo >&2 -e "${CInfo:-}Disk attached: ${CData:-}$hd_path${CReset:-}" + vm_detach_disk "$vm_name" + disk_unregister "$hd_path" + echo >&2 -e "Deleting: $hd_path" + rm -f "$hd_path" + fi + vm_unregister_del "$vm_name" + else + echo >&2 "(not found)" + fi +} + +# Remove VMs using disk and its children disks +# disk can be either a path or a disk UUID +function disk_delete_child_vms { + local disk=$1 + if ! disk_registered "$disk"; then + # VirtualBox doesn't know this disk; we are done + echo >&2 -e "${CError:-}Disk not registered with VirtualBox:\n\t${CData:-}$disk${CReset:-}" + return 0 + fi + + # XXX temporary hack + # No Child UUIDs through showhdinfo in VirtualBox 4.1 (Mac OS X 10.5) + local ver=$(get_vb_version) + if [[ $ver == 4.1* ]]; then + local vm_name="" + for vm_name in controller network compute base; do + vm_delete "$vm_name" + done + return 0 + fi + + while [ : ]; do + local child_uuid=$(get_next_child_uuid "$disk") + if [ -n "$child_uuid" ]; then + local child_disk="$(disk_to_path "$child_uuid")" + echo >&2 -e "\nChild disk UUID: $child_uuid\n\t$child_disk" + + local vm_name="$(disk_to_vm "$child_uuid")" + if [ -n "$vm_name" ]; then + echo 2>&1 -e "\tstill attached to VM \"$vm_name\"" + vm_delete "$vm_name" + else + echo -e >&2 "${CStatus:-}Unregistering and deleting: ${CData:-}$child_uuid${CReset:-}" + disk_unregister "$child_uuid" + echo >&2 -e "\t$child_disk" + rm -f "$child_disk" + fi + else + break + fi + done +} + +#------------------------------------------------------------------------------- +# VM shared folders +#------------------------------------------------------------------------------- + +# Return the host path for a VM's shared directory; assumes there is only one. +function vm_get_share_path { + local vm_name=$1 + local line=$(WBATCH= $VBM showvminfo --machinereadable "$vm_name" | \ + grep '^SharedFolderPathMachineMapping1=') + local share_path=${line##SharedFolderPathMachineMapping1=\"} + share_path=${share_path%\"} + echo "$share_path" +} + +function vm_add_share_automount { + local vm_name=$1 + local share_dir=$2 + local share_name=$3 + $VBM sharedfolder add "$vm_name" \ + --name "$share_name" \ + --hostpath "$share_dir" \ + --automount +} + +function vm_add_share { + local vm_name=$1 + local share_dir=$2 + local share_name=$3 + $VBM sharedfolder add "$vm_name" \ + --name "$share_name" \ + --hostpath "$share_dir" +} + +function vm_rm_share { + local vm_name=$1 + local share_name=$2 + $VBM sharedfolder remove "$vm_name" --name "$share_name" +} + +#------------------------------------------------------------------------------- +# VirtualBox guest add-ons +#------------------------------------------------------------------------------- + +# Download VirtualBox guest-additions. Returns local path of ISO image. +function _download_guestadd-iso { + local iso=VBoxGuestAdditions.iso + local ver=$(get_vb_version) + if [[ -n "$ver" ]]; then + local url="http://download.virtualbox.org/virtualbox/$ver/VBoxGuestAdditions_$ver.iso" + download "$url" "$ISO_DIR" $iso + fi + echo "$ISO_DIR/$iso" +} + +function _get_guestadd-iso { + local iso=VBoxGuestAdditions.iso + + local add_iso="$IMG_DIR/$iso" + if [ -f "$add_iso" ]; then + echo "$add_iso" + return 0 + fi + + add_iso="/Applications/VirtualBox.app/Contents/MacOS/$iso" + if [ -f "$add_iso" ]; then + echo "$add_iso" + return 0 + fi + + echo >&2 "Searching filesystem for VBoxGuestAdditions. This may take a while..." + add_iso=$(find / -name "$iso" 2>/dev/null) || true + if [ -n "$add_iso" ]; then + echo "$add_iso" + return 0 + fi + + echo >&2 "Looking on the Internet" + add_iso=$(_download_guestadd-iso) + if [ -f "$add_iso" ]; then + echo "$add_iso" + return 0 + fi +} + +function _vm_attach_guestadd-iso { + local vm_name=$1 + local guestadd_iso=$2 + local rc=0 + $VBM storageattach "$vm_name" --storagectl IDE --port 1 --device 0 --type dvddrive --medium "$guestadd_iso" 2>/dev/null || rc=$? + return $rc +} + +function vm_attach_guestadd-iso { + local vm_name=$1 + + OSBASH= ${WBATCH:-:} _vm_attach_guestadd-iso "$vm_name" emptydrive + OSBASH= ${WBATCH:-:} _vm_attach_guestadd-iso "$vm_name" additions + # Return if we are just faking it for wbatch + ${OSBASH:+:} return 0 + + if [ -z "${GUESTADD_ISO-}" ]; then + + # No location provided, asking VirtualBox for one + + # An existing drive is needed to make additions shortcut work + # (at least VirtualBox 4.3.12 and below) + WBATCH= _vm_attach_guestadd-iso "$vm_name" emptydrive + + if WBATCH= _vm_attach_guestadd-iso "$vm_name" additions; then + echo >&2 "Using VBoxGuestAdditions provided by VirtualBox" + return 0 + fi + # Neither user nor VirtualBox are helping, let's go guessing + GUESTADD_ISO=$(_get_guestadd-iso) + if [ -z "GUESTADD_ISO" ]; then + # No ISO found + return 2 + fi + fi + if WBATCH= _vm_attach_guestadd-iso "$vm_name" "$GUESTADD_ISO"; then + echo >&2 "Attached $GUESTADD_ISO" + return 0 + else + echo -e >&2 "${CError:-}Failed to attach ${CData:-}$GUESTADD_ISO${CReset:-}" + return 3 + fi +} + +#------------------------------------------------------------------------------- +# Sleep +#------------------------------------------------------------------------------- + +function vbox_sleep { + sec=$1 + + # Don't sleep if we are just faking it for wbatch + ${OSBASH:-:} sleep "$sec" + ${WBATCH:-:} wbatch_sleep "$sec" +} + +#------------------------------------------------------------------------------- +# Booting a VM and passing boot parameters +#------------------------------------------------------------------------------- + +source "$OSBASH_LIB_DIR/scanlib.sh" + +function _vbox_push_scancode { + local vm_name=$1 + shift + # Split string (e.g. '01 81') into arguments (works also if we + # get each hexbyte as a separate argument) + # Not quoting $@ is intentional -- we want to split on blanks + local scan_code=( $@ ) + $VBM controlvm "$vm_name" keyboardputscancode "${scan_code[@]}" +} + +function vbox_kbd_escape_key { + local vm_name=$1 + _vbox_push_scancode "$vm_name" "$(esc2scancode)" +} + +function vbox_kbd_enter_key { + local vm_name=$1 + _vbox_push_scancode "$vm_name" "$(enter2scancode)" +} + +function vbox_kbd_string_input { + local vm_name=$1 + local str=$2 + + # This loop is inefficient enough that we don't overrun the keyboard input + # buffer when pushing scancodes to the VirtualBox. + while IFS= read -r -n1 char; do + if [ -n "$char" ]; then + SC=$(char2scancode "$char") + if [ -n "$SC" ]; then + _vbox_push_scancode "$vm_name" "$SC" + else + echo >&2 "not found: $char" + fi + fi + done <<< "$str" +} + +function vbox_boot { + local vm_name=$1 + + echo -e >&2 "${CStatus:-}Starting VM ${CData:-}\"$vm_name\"${CReset:-}" + if [ -n "${VM_UI:-}" ]; then + $VBM startvm "$vm_name" --type "$VM_UI" + else + $VBM startvm "$vm_name" + fi +} + +#------------------------------------------------------------------------------- + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash/virtualbox-install_base.sh b/labs/osbash/lib/osbash/virtualbox-install_base.sh new file mode 100644 index 00000000..743d33ea --- /dev/null +++ b/labs/osbash/lib/osbash/virtualbox-install_base.sh @@ -0,0 +1,145 @@ +# This bash library contains the main function that creates the base disk. + +function check_md5 { + local file=$1 + local csum=$2 + local md5exe + if ! md5exe=$(which md5sum); then + # On Mac OS X, the tool is called md5 + if ! md5exe=$(which md5); then + echo -e >&2 "${CError:-}Neither md5sum nor md5 found. Aborting.${CReset:-}" + exit 1 + fi + fi + echo -e >&2 -n "${CStatus:-}Verifying ISO image MD5 checksum: ${CReset:-}" + if $md5exe "$file" | grep -q "$csum"; then + echo >&2 "okay." + else + echo -e >&2 "${CError:-}Verification failed. ISO image is corrupt.${CReset:-}" + echo >&2 "Removing the ISO image." + rm "$file" + echo -e >&2 "${CError:-}Please re-run osbash script.${CReset:-}" + exit 1 + fi +} + +function vm_install_base { + local base_disk=$1 + local base_build_disk=$DISK_DIR/tmp-disk.vdi + local vm_name=base + + # Port used for ssh forwarding when building base disk + : ${VM_BASE_SSH_PORT:=2229} + + echo >&2 "$(date) osbash vm_install starts." + + ${WBATCH:-:} wbatch_begin_base + + # Don't remove base_build_disk if we are just faking it for wbatch + ${OSBASH:-:} rm -f "$base_build_disk" + ${WBATCH:-:} wbatch_delete_disk "$base_build_disk" + + vm_create "$vm_name" + vm_mem "$vm_name" "${VM_BASE_MEM:=512}" + + if [ -z "${INSTALL_ISO-}" ]; then + local iso_name="$(get_iso_name)" + + if [ -z "$iso_name" ]; then + echo -e >&2 "${CMissing:-}Either ISO URL or name needed (ISO_URL, INSTALL_ISO).${CReset:-}" + exit 1 + fi + INSTALL_ISO=$ISO_DIR/$iso_name + # Don't look for ISO image if we are only doing wbatch + ${OSBASH:-:} find_install-iso "$iso_name" + fi + + echo >&2 -e "${CInfo:-}Install ISO:\n\t${CData:-}$INSTALL_ISO${CReset:-}" + + ${OSBASH:-:} check_md5 "$INSTALL_ISO" "$ISO_MD5" + + $VBM storageattach "$vm_name" \ + --storagectl IDE \ + --port 0 \ + --device 0 \ + --type dvddrive \ + --medium "$INSTALL_ISO" + + ${WBATCH:-:} vm_attach_guestadd-iso "$vm_name" + + ${OSBASH:-:} mkdir -pv "$DISK_DIR" + create_vdi "$base_build_disk" "${BASE_DISK_SIZE:=10000}" + vm_attach_disk "$vm_name" "$base_build_disk" + + #--------------------------------------------------------------------------- + # Set up communication with base VM: ssh port forwarding by default, + # VirtualBox shared folders for wbatch + + # wbatch runs cannot use ssh, so skip port forwarding in that case + ${WBATCH:+:} vm_port "$vm_name" ssh "$VM_BASE_SSH_PORT" 22 + + # Automounted on /media/sf_bootstrap for first boot + ${WBATCH:-:} vm_add_share_automount "$vm_name" "$SHARE_DIR" bootstrap + # Mounted on /$SHARE_NAME after first boot + ${WBATCH:-:} vm_add_share "$vm_name" "$SHARE_DIR" "$SHARE_NAME" + #--------------------------------------------------------------------------- + + $VBM modifyvm "$vm_name" --boot1 dvd + + # Configure autostart + autostart_reset + + # For wbatch, install osbashauto as a boot service + ${WBATCH:-:} autostart osbash/activate_autostart.sh + + autostart osbash/base_fixups.sh + + # By default, set by lib/osbash/lib.* to something like scripts.ubuntu_base + autostart_from_config "$BASE_INSTALL_SCRIPTS" + + autostart zero_empty.sh shutdown.sh + + # Boot VM into distribution installer + vbox_boot "$vm_name" + + local delay=5 + echo >&2 "Waiting $delay seconds for VM \"$vm_name\" to come up" + vbox_sleep "$delay" + + vbox_distro_start_installer "$vm_name" + + echo -e >&2 "${CStatus:-}Installing operating system; waiting for reboot${CReset:-}" + + # Wait for ssh connection and execute scripts in autostart directory + # (for wbatch, osbashauto does the processing instead) + ${WBATCH:+:} ssh_process_autostart "$VM_BASE_SSH_PORT" & + # After reboot + wait_for_autofiles + echo -e >&2 "${CStatus:-}Installation done for VM ${CData:-}$vm_name${CReset:-}" + + vm_wait_for_shutdown "$vm_name" + + # Detach disk from VM now or it will be deleted by vm_unregister_del + vm_detach_disk "$vm_name" + + vm_unregister_del "$vm_name" + + echo >&2 "Compacting $base_build_disk" + $VBM modifyhd "$base_build_disk" --compact + + # This disk will be moved to a new name, and this name will be used for + # a new disk next time the script runs. + disk_unregister "$base_build_disk" + + echo -e >&2 "${CStatus:-}Base disk created${CReset:-}" + + echo >&2 "Moving base disk to $base_disk" + ${OSBASH:-:} mv -vf "$base_build_disk" "$base_disk" + ${WBATCH:-:} wbatch_rename_disk "$base_build_disk" "$base_disk" + + ${WBATCH:-:} wbatch_end_file + + echo >&2 -e "${CData:-}$(date) ${CStatus:-}osbash vm_install ends\n${CReset:-}" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/osbash/virtualbox-install_nodes.sh b/labs/osbash/lib/osbash/virtualbox-install_nodes.sh new file mode 100644 index 00000000..51ef6581 --- /dev/null +++ b/labs/osbash/lib/osbash/virtualbox-install_nodes.sh @@ -0,0 +1,86 @@ +# This bash library contains the main function that creates a node VM. + +# Configure VirtualBox network interfaces +function _vbox_configure_ifs { + local vm_name=$1 + # Iterate over all NET_IF_? variables + local net_ifs=( "${!NET_IF_@}" ) + local net_if="" + for net_if in "${net_ifs[@]}"; do + local if_num=${net_if##*_} + if [ "${!net_if}" = "nat" ]; then + echo "interface $if_num: NAT" + vm_nic_nat "$vm_name" "$if_num" + else + # Host-only network: net_if is net name (e.g. API_NET) + # Use corresponding VirtualBox interface (e.g. API_NET_IF) + local host_if="${!net_if}_IF" + echo "interface $if_num: host-only ${!host_if}" + vm_nic_hostonly "$vm_name" "$if_num" "${!host_if}" + fi + done +} + +# Boot node VM; wait until autostart files are processed and VM is shut down +function _vbox_boot_with_autostart { + local vm_name=$1 + + vbox_boot "$vm_name" + + # Wait for ssh connection and execute scripts in autostart directory + # (for wbatch, osbashauto does the processing instead) + ${WBATCH:+:} ssh_process_autostart "$vm_name" & + + wait_for_autofiles + echo >&2 "VM \"$vm_name\": autostart files executed" +} + +# Create a new node VM and run basic configuration scripts +function vm_init_node { + # XXX Run this function in sub-shell to protect our caller's environment + # (which might be _our_ enviroment if we get called again) + ( + source "$CONFIG_DIR/config.$vm_name" + + vm_name=$1 + + vm_create "$vm_name" + + # Set VM_MEM in config/config.NODE_NAME to override + vm_mem "$vm_name" "${VM_MEM:-512}" + + # Set VM_CPUS in config/config.NODE_NAME to override + vm_cpus "$vm_name" "${VM_CPUS:-1}" + + _vbox_configure_ifs "$vm_name" + + # Port forwarding + if [ -n "${VM_SSH_PORT:-}" ]; then + vm_port "$vm_name" ssh "$VM_SSH_PORT" 22 + fi + if [ -n "${VM_WWW_PORT:-}" ]; then + vm_port "$vm_name" http "$VM_WWW_PORT" 80 + fi + + vm_add_share "$vm_name" "$SHARE_DIR" "$SHARE_NAME" + vm_attach_disk_multi "$vm_name" "$BASE_DISK" + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + # Rename to pass the node name to the script + autostart_and_rename osbash init_xxx_node.sh "init_${vm_name}_node.sh" + + ) +} + +function vm_build_nodes { + CONFIG_NAME=$(get_distro_name "$DISTRO")_$1 + echo -e "${CInfo:-}Configuration file: ${CData:-}$CONFIG_NAME${CReset:-}" + + ${WBATCH:-:} wbatch_begin_node "$CONFIG_NAME" + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + autostart_reset + autostart_from_config "scripts.$CONFIG_NAME" + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ${WBATCH:-:} wbatch_end_file +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/wbatch/README.rst b/labs/osbash/lib/wbatch/README.rst new file mode 100644 index 00000000..03423220 --- /dev/null +++ b/labs/osbash/lib/wbatch/README.rst @@ -0,0 +1,2 @@ +The files in this directory are used to create Windows batch scripts that +can build base disks and VM clusters. diff --git a/labs/osbash/lib/wbatch/batch_for_windows.sh b/labs/osbash/lib/wbatch/batch_for_windows.sh new file mode 100644 index 00000000..1b8f7540 --- /dev/null +++ b/labs/osbash/lib/wbatch/batch_for_windows.sh @@ -0,0 +1,298 @@ +# This bash library contains the functions that allow osbash to produce +# Windows batch files. + +: ${WBATCH_DIR:="$TOP_DIR/wbatch"} + +# By default, Windows batch file templates are in the same directory as this +# file +: ${WBATCH_TEMPLATE_DIR:=$(dirname "$BASH_SOURCE")} + +# wbatch cannot use ssh for talking to the VM; install VirtualBox guest +# additions +VM_ACCESS=vbadd + +#------------------------------------------------------------------------------- +# Helper functions +#------------------------------------------------------------------------------- + +# See functions.host for definition and explanation of exec_cmd +WBATCH=exec_cmd + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +function wbatch_reset { + clean_dir "$WBATCH_DIR" +} + +function wbatch_new_file { + local file_name=$1 + mkdir -p "$WBATCH_DIR" + WBATCH_OUT="$WBATCH_DIR/$file_name" + echo -n > "$WBATCH_OUT" +} + +function wbatch_close_file { + unset WBATCH_OUT +} + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +function wbatch_write_line { + if [ -n "${WBATCH_OUT:-}" ]; then + # Don't expand backslash escapes except for ending the line with CRLF + # + # Note: Windows batch scripts with LF may seem to work, but (for + # instance) jump labels don't work properly + echo -n "$@" >> "$WBATCH_OUT" + echo -e "\r" >> "$WBATCH_OUT" + fi +} + +function wbatch_write_stdin { + local line="" + + # Set IFS to preserve leading whitespace + while IFS= read -r line; do + wbatch_write_line "$line" + done +} + +function wbatch_echo { + wbatch_write_line "ECHO %time% $@" +} + +#------------------------------------------------------------------------------- +# Batch function calls +#------------------------------------------------------------------------------- + +function wbatch_abort_if_vm_exists { + local vm_name=$1 + wbatch_write_line "CALL :vm_exists $vm_name" +} + +function wbatch_wait_poweroff { + local vm_name=$1 + cat << WBAT | wbatch_write_stdin +ECHO %time% Waiting for VM $vm_name to power off. +CALL :wait_poweroff $vm_name +ECHO %time% VM $vm_name powered off. +WBAT +} + +function wbatch_wait_auto { + cat << WBAT | wbatch_write_stdin +ECHO %time% Waiting for autostart files to execute. +CALL :wait_auto +ECHO %time% All autostart files executed. +WBAT +} + +#------------------------------------------------------------------------------- +# Batch commands +#------------------------------------------------------------------------------- + +function wbatch_delete_disk { + local disk=$(basename "$1") + wbatch_write_line "IF EXIST %IMGDIR%\\$disk DEL %IMGDIR%\\$disk" +} + +function wbatch_rename_disk { + local src=$(basename "$1") + local target=$(basename "$2") + + wbatch_write_line "MOVE /y %IMGDIR%\\$src %IMGDIR%\\$target" +} + +function wbatch_cp_auto { + local src=$(wbatch_path_to_windows "$1") + local target=$(basename "$2") + src=${src//\//\\} + wbatch_write_line "COPY %TOPDIR%\\$src %AUTODIR%\\$target" +} + +function wbatch_sleep { + local sec=$1 + wbatch_write_line "TIMEOUT /T $sec /NOBREAK" +} + +#------------------------------------------------------------------------------- +# Templated parts +#------------------------------------------------------------------------------- + +# Note: BSD and GNU sed behavior is different. Don't try anything fancy +# like inserting \r or in-place editing (-i). + +function wbatch_file_header { + local product=$1 + + sed -e " + s,%PRODUCT%,$product,g; + " "$WBATCH_TEMPLATE_DIR/template-file_header_bat" | wbatch_write_stdin +} + +function wbatch_end_file { + cat "$WBATCH_TEMPLATE_DIR/template-end_file_bat" | wbatch_write_stdin + wbatch_close_file +} + +function wbatch_elevate_privileges { + cat "$WBATCH_TEMPLATE_DIR/template-elevate_privs_bat" | wbatch_write_stdin +} + +function wbatch_find_vbm { + cat "$WBATCH_TEMPLATE_DIR/template-find_vbm_bat" | wbatch_write_stdin +} + +function wbatch_mkdirs { + local autodir=$(wbatch_path_to_windows "$AUTOSTART_DIR") + local imgdir=$(wbatch_path_to_windows "$IMG_DIR") + local logdir=$(wbatch_path_to_windows "$LOG_DIR") + local statusdir=$(wbatch_path_to_windows "$STATUS_DIR") + + autodir="$(wbatch_escape_backslash "$autodir")" + imgdir="$(wbatch_escape_backslash "$imgdir")" + logdir="$(wbatch_escape_backslash "$logdir")" + statusdir="$(wbatch_escape_backslash "$statusdir")" + + sed -e " + s,%P_AUTODIR%,$autodir,g; + s,%P_IMGDIR%,$imgdir,g; + s,%P_LOGDIR%,$logdir,g; + s,%P_STATUSDIR%,$statusdir,g; + " "$WBATCH_TEMPLATE_DIR/template-mkdirs_bat" | wbatch_write_stdin +} + +function wbatch_create_hostnet { + wbatch_new_file "create_hostnet.bat" + wbatch_file_header "host-only networks" + # Creating networks requires elevated privileges + wbatch_elevate_privileges + wbatch_find_vbm + + sed -e " + s,%APINET%,$API_NET,g; + s,%DATANET%,$DATA_NET,g; + s,%MGMTNET%,$MGMT_NET,g; + " "$WBATCH_TEMPLATE_DIR/template-create_hostnet_bat" | wbatch_write_stdin + + wbatch_end_file +} + +function wbatch_begin_base { + local iso_name=$(get_iso_name) + + if [ -z "$iso_name" ]; then + echo >&2 "Windows batch file needs install ISO URL (ISO_URL)." + exit 1 + fi + + wbatch_new_file "create_base.bat" + wbatch_file_header "base disk" + wbatch_find_vbm + wbatch_mkdirs + + sed -e " + s,%INSTALLFILE%,$iso_name,g; + s,%ISOURL%,$ISO_URL,g; + " "$WBATCH_TEMPLATE_DIR/template-begin_base_bat" | wbatch_write_stdin +} + +function wbatch_begin_node { + local node_name=$1 + wbatch_new_file "create_${node_name}_node.bat" + wbatch_file_header "$node_name VM" + wbatch_find_vbm + wbatch_mkdirs + + local basedisk=$(basename "$BASE_DISK") + + sed -e " + s,%BASEDISK%,$basedisk,g; + " "$WBATCH_TEMPLATE_DIR/template-begin_node_bat" | wbatch_write_stdin +} + +#------------------------------------------------------------------------------- +# VBoxManage call handling +#------------------------------------------------------------------------------- + +function wbatch_get_hostif_subst { + local hostif=$1 + case "$hostif" in + ${MGMT_NET_IF:-""}) + echo 'VirtualBox Host-Only Ethernet Adapter' + ;; + ${DATA_NET_IF:-""}) + echo 'VirtualBox Host-Only Ethernet Adapter #2' + ;; + ${API_NET_IF:-""}) + echo 'VirtualBox Host-Only Ethernet Adapter #3' + ;; + *) + return 1 + ;; + esac +} + +function wbatch_log_vbm { + ARGS=( "$@" ) + for i in "${!ARGS[@]}"; do + case "${ARGS[i]}" in + --hostonlyadapter*) + # The next arg is the host-only interface name -> change it + ARGS[i+1]=\"$(wbatch_get_hostif_subst "${ARGS[i+1]}")\" + ;; + --hostpath) + # The next arg is the shared dir -> change it + ARGS[i+1]='%SHAREDIR%' + continue + ;; + esac + + # On Windows, ISO and base disk images must be in IMGDIR + re='\.(iso|vdi)$' + if [[ "${ARGS[i]}" =~ $re ]]; then + local img_name=$(basename "${ARGS[i]}") + ARGS[i]="%IMGDIR%\\$img_name" + continue + fi + done + + # Echo what we are about to do + wbatch_write_line "ECHO VBoxManage ${ARGS[@]}" + + wbatch_write_line "VBoxManage ${ARGS[@]}" + + # Abort if VBoxManage call raised errorlevel + wbatch_write_line "IF %errorlevel% NEQ 0 GOTO :vbm_error" + + # Blank line for readability + wbatch_write_line "" +} + +#------------------------------------------------------------------------------- +# Windows path name helpers +#------------------------------------------------------------------------------- + +# On Windows, all paths are relative to TOP_DIR +function wbatch_path_to_windows { + local full_path=$1 + # strip off ${TOP_DIR}/ + full_path="${full_path/$TOP_DIR\//}" + full_path=$(wbatch_slash_to_backslash "$full_path") + echo "$full_path" +} + +# Escape backslashes in (path) variables that are given to sed +function wbatch_escape_backslash { + local string=$1 + string="${string//\\/\\\\}" + echo "$string" +} + +function wbatch_slash_to_backslash { + local some_path=$1 + some_path="${some_path//\//\\}" + echo "$some_path" +} + +# vim: set ai ts=4 sw=4 et ft=sh: diff --git a/labs/osbash/lib/wbatch/template-begin_base_bat b/labs/osbash/lib/wbatch/template-begin_base_bat new file mode 100644 index 00000000..33d558c9 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-begin_base_bat @@ -0,0 +1,37 @@ +ECHO %time% Cleaning up autostart and log directories +DEL /S /Q %AUTODIR% +DEL /S /Q %LOGDIR% + +ECHO %time% Looking for %IMGDIR%\%INSTALLFILE% +IF EXIST %IMGDIR%\%INSTALLFILE% goto got_install_iso + +ECHO. +ECHO %INSTALLFILE% not found in %IMGDIR%. +ECHO. +ECHO Trying to download the install ISO from +ECHO %ISOURL% +ECHO. +ECHO Expect this to take several minutes or longer, depending on your +ECHO Internet connection. +ECHO. +cscript /nologo %TOOLSDIR%\downloader.js %ISOURL% +RENAME downloaded.bin %INSTALLFILE% +MOVE %INSTALLFILE% %IMGDIR% +IF EXIST %IMGDIR%\%INSTALLFILE% goto got_install_iso +ECHO. +ECHO %INSTALLFILE% still not found in %IMGDIR%. +ECHO Aborting. +ECHO. + +goto :terminate + +:got_install_iso +ECHO. +ECHO %time% Found %IMGDIR%\%INSTALLFILE% +ECHO. +ECHO %time% Initialization done. Hit any key to continue. +ECHO. +PAUSE + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-begin_node_bat b/labs/osbash/lib/wbatch/template-begin_node_bat new file mode 100644 index 00000000..530b71c7 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-begin_node_bat @@ -0,0 +1,23 @@ +ECHO %time% Cleaning up autostart and log directories +DEL /S /Q %AUTODIR% +DEL /S /Q %LOGDIR% + +ECHO %time% Looking for %IMGDIR%\%BASEDISK% +IF EXIST %IMGDIR%\%BASEDISK% goto got_base_disk +ECHO. +ECHO %BASEDISK% not found in %IMGDIR%. +ECHO. +ECHO You need to build a base disk before you can create node VMs. +ECHO. +goto :terminate + +:got_base_disk +ECHO. +ECHO %time% Found %IMGDIR%\%BASEDISK% +ECHO. +ECHO %time% Initialization done. Hit any key to continue. +ECHO. +PAUSE + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-create_hostnet_bat b/labs/osbash/lib/wbatch/template-create_hostnet_bat new file mode 100644 index 00000000..867ba0b0 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-create_hostnet_bat @@ -0,0 +1,31 @@ +ECHO. +ECHO %time% Initialization done. Hit any key to continue. +ECHO. +PAUSE + +ECHO VBoxManage hostonlyif create +VBoxManage hostonlyif create +IF %errorlevel% NEQ 0 GOTO :vbm_error + +ECHO VBoxManage hostonlyif ipconfig "VirtualBox Host-Only Ethernet Adapter" --ip %MGMTNET% --netmask 255.255.255.0 +VBoxManage hostonlyif ipconfig "VirtualBox Host-Only Ethernet Adapter" --ip %MGMTNET% --netmask 255.255.255.0 +IF %errorlevel% NEQ 0 GOTO :vbm_error + +ECHO VBoxManage hostonlyif create +VBoxManage hostonlyif create +IF %errorlevel% NEQ 0 GOTO :vbm_error + +ECHO VBoxManage hostonlyif ipconfig "VirtualBox Host-Only Ethernet Adapter #2" --ip %DATANET% --netmask 255.255.255.0 +VBoxManage hostonlyif ipconfig "VirtualBox Host-Only Ethernet Adapter #2" --ip %DATANET% --netmask 255.255.255.0 +IF %errorlevel% NEQ 0 GOTO :vbm_error + +ECHO VBoxManage hostonlyif create +VBoxManage hostonlyif create +IF %errorlevel% NEQ 0 GOTO :vbm_error + +ECHO VBoxManage hostonlyif ipconfig "VirtualBox Host-Only Ethernet Adapter #3" --ip %APINET% --netmask 255.255.255.0 +VBoxManage hostonlyif ipconfig "VirtualBox Host-Only Ethernet Adapter #3" --ip %APINET% --netmask 255.255.255.0 +IF %errorlevel% NEQ 0 GOTO :vbm_error + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-elevate_privs_bat b/labs/osbash/lib/wbatch/template-elevate_privs_bat new file mode 100644 index 00000000..e6df3632 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-elevate_privs_bat @@ -0,0 +1,26 @@ +REM Elevate credentials, code courtesy of Matthew Newton +REM http://blog.mnewton.com/articles/Windows-Installer-Batch-Script-Revisited.html +REM Check for permissions +>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" + +REM If error flag set, we do not have admin. +if '%errorlevel%' NEQ '0' ( + echo Requesting administrative privileges... + goto UACPrompt +) else ( goto gotAdmin ) + + +:UACPrompt + echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs" + echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs" + + "%temp%\getadmin.vbs" + REM we are done, exiting recursive call + exit /B + +:gotAdmin + if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" ) + echo We have admin privileges, proceeding... + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-end_file_bat b/labs/osbash/lib/wbatch/template-end_file_bat new file mode 100644 index 00000000..ee732fe9 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-end_file_bat @@ -0,0 +1,59 @@ +ECHO. +ECHO %time% Batch script seems to have succeeded. +ECHO. + +GOTO :terminate + +REM Note: vbm_error falls through to terminate +:vbm_error +ECHO. +ECHO %time% VBoxManage returned with an error. Aborting. +ECHO. + +:terminate +ENDLOCAL +PAUSE +EXIT +GOTO :eof + +REM ============================================================================ +REM +REM End of program, function definitions follow +REM +REM ============================================================================ +:wait_auto +IF EXIST %STATUSDIR%\done ( + DEL %STATUSDIR%\done + GOTO :eof +) +IF EXIST %STATUSDIR%\error ( + ECHO. + ECHO %time% ERROR Script returned error: + ECHO. + TYPE %STATUSDIR%\error + ECHO. + ECHO %time% Aborting. + ECHO. + DEL %STATUSDIR%\error + GOTO :terminate +) +TIMEOUT /T 5 /NOBREAK +GOTO :wait_auto +REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +:wait_poweroff +VBoxManage showvminfo %~1 --machinereadable|findstr poweroff +IF %errorlevel% EQU 0 GOTO :eof +TIMEOUT /T 2 /NOBREAK +GOTO :wait_poweroff +REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +:vm_exists +VBoxManage list vms|findstr %~1 +IF %errorlevel% NEQ 0 GOTO :eof +ECHO. +ECHO %time% VM %~1 already exists. Aborting. +ECHO. +GOTO :terminate +REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-file_header_bat b/labs/osbash/lib/wbatch/template-file_header_bat new file mode 100644 index 00000000..81e8f0c8 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-file_header_bat @@ -0,0 +1,16 @@ +@ECHO OFF + +REM This is an automatically generated Windows batch file. It creates the +REM %PRODUCT% for an OpenStack training-labs setup. + +SETLOCAL ENABLEDELAYEDEXPANSION + +ECHO. +ECHO OpenStack labs for VirtualBox on Windows +ECHO Generated by osbash +ECHO. +ECHO Create %PRODUCT% +ECHO. + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-find_vbm_bat b/labs/osbash/lib/wbatch/template-find_vbm_bat new file mode 100644 index 00000000..8a66ea53 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-find_vbm_bat @@ -0,0 +1,30 @@ +REM VBoxManage is not in PATH, but this is a good guess +IF EXIST %ProgramFiles%\Oracle\VirtualBox\VBoxManage.exe ( + SET PATH=%PATH%;%ProgramFiles%\Oracle\VirtualBox + ECHO. + ECHO %time% Found %ProgramFiles%\Oracle\VirtualBox\VBoxManage.exe + ECHO. + GOTO :vbm_found +) + +ECHO. +ECHO %time% Searching %SystemDrive% for VBoxManage, this may take a while +ECHO. +FOR /r %SystemDrive% %%a IN (*) DO ( + IF "%%~nxa"=="VBoxManage.exe" ( + SET PATH=%PATH%;%%~dpa + ECHO %time% Found %%~dpnxa + GOTO :vbm_found + ) +) + +ECHO. +ECHO %time% Cannot find VBoxManage.exe (part of VirtualBox) on %SystemDrive%. +ECHO %time% Program stops. +ECHO. +GOTO :terminate + +:vbm_found + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: + diff --git a/labs/osbash/lib/wbatch/template-mkdirs_bat b/labs/osbash/lib/wbatch/template-mkdirs_bat new file mode 100644 index 00000000..192240d4 --- /dev/null +++ b/labs/osbash/lib/wbatch/template-mkdirs_bat @@ -0,0 +1,20 @@ +SET BATDIR=%~dp0 +PUSHD %BATDIR%.. +SET TOPDIR=%cd% +POPD + +SET AUTODIR=%TOPDIR%\%P_AUTODIR% +SET IMGDIR=%TOPDIR%\%P_IMGDIR% +SET LOGDIR=%TOPDIR%\%P_LOGDIR% +SET STATUSDIR=%TOPDIR%\%P_STATUSDIR% +SET SHAREDIR=%TOPDIR% +SET TOOLSDIR=%TOPDIR%\tools + +ECHO %time% Creating directories (if needed) +IF NOT EXIST %AUTODIR% mkdir %AUTODIR% +IF NOT EXIST %IMGDIR% mkdir %IMGDIR% +IF NOT EXIST %LOGDIR% mkdir %LOGDIR% +IF NOT EXIST %SHAREDIR% mkdir %SHAREDIR% + +REM vim: set ai ts=4 sw=4 et ft=dosbatch: +