training-labs/labs/osbash/lib/wbatch/batch_for_windows.sh

298 lines
8.4 KiB
Bash

# 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
# With VirtualBox 5.1.6, console type "headless" often gives no access to the
# VM console which on Windows is the main method for interacting with the
# cluster. Use "separate" which works at least on 5.0.26 and 5.1.6.
VM_UI=separate
#-------------------------------------------------------------------------------
# Helper functions
#-------------------------------------------------------------------------------
# See functions.host for definition and explanation of exec_cmd
WBATCH=exec_cmd
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function wbatch_reset {
clean_dir "$WBATCH_DIR"
cp -v "$WBATCH_TEMPLATE_DIR/config_bat" "$WBATCH_DIR/config.bat"
}
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"
cat "$WBATCH_TEMPLATE_DIR/template-begin_hostnet_bat" | wbatch_write_stdin
# Creating networks requires elevated privileges
wbatch_elevate_privileges
wbatch_find_vbm
local index
local if_name
local win_adapter
for index in "${!NET_NAME[@]}"; do
if_name=${NET_IFNAME[index]}
# The host-side interface is the default gateway of the network
if_ip=${NET_GW[index]}
# Translate if_name to Windows-type interface name
win_adapter=$if_name
sed -e "
s,%IFNAME%,${win_adapter},g;
s,%IFIP%,${if_ip},g;
" "$WBATCH_TEMPLATE_DIR/template-create_hostnet_bat" | wbatch_write_stdin
echo | wbatch_write_stdin
done
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=$(get_base_disk_name).vdi
sed -e "
s,%BASEDISK%,$basedisk,g;
" "$WBATCH_TEMPLATE_DIR/template-begin_node_bat" | wbatch_write_stdin
}
#-------------------------------------------------------------------------------
# VBoxManage call handling
#-------------------------------------------------------------------------------
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]=\"%${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 "\"%VBM%\" ${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: