Commit fc8828d6 authored by Nikos Skalkotos's avatar Nikos Skalkotos
Browse files

Merge tag 'v0.7' into debian-0.7

Release v0.7
parents 26f7e336 a7a7b869
2012-12-03, v0.6.5
* Make snf-image-helper the init process of the system
* Shutdown the helper image fast using the apropriate SysRq key
* Use eatmydata to omit the syncs performed by resize2fs when
resizing a file system. You can supress this behaviour by defining
the DO_SYNC image property.
2012-11-20, v0.6.5
* Fix a bug in AssignHostname configuration task where the script did
not search for the presence of the Unattend.xml file in the VM, in
a case-insensitive way
2012-11-15, v0.6.4
2012-11-13, v0.6.3
* Don't overwrite C:\Unattend.xml file in windows images, unless the
image property USE_DEFAULT_UNATTEND is defined.
* Fix a bug in the error monitoring system
* Correct some error messages
2012-10-12, v0.6.2
* Remove the rule of updating the password for user `user' in Fedora
and Ubuntu when the USERS image property is missing.
* Check if a user exists before updating its password.
2012-10-05, v0.6.1
* Supress a very noisy warning in 40DisableRemoteDesktopConnections
task created by reglookup. This is triggered only when reading
registry files from windows 2012 systems.
* User Coordinated Universal Time when logging.
2012-09-14, v0.6
* Make sure EnforcePersonality is the last task that runs before
UmountImage. Doing this ensures that user-enjected files never
get overwritten by any other configuration task.
2012-08-31, v0.5
* Add a new progress monitoring mechanish
* Add support for arch linux
......
......@@ -35,6 +35,8 @@ BLKID=blkid
BLOCKDEV=blockdev
REGLOOKUP=reglookup
CHNTPW=chntpw
DATE="date -u" # Time in UTC
EATMYDATA=eatmydata
CLEANUP=( )
ERRORS=( )
......@@ -51,9 +53,24 @@ add_cleanup() {
CLEANUP+=("$cmd")
}
report_error() {
if [ ${#ERRORS[*]} -eq 0 ]; then
# No error message. Print stderr
local lines
lines=$(tail --lines=${STDERR_LINE_SIZE} "$STDERR_FILE" | wc -l)
echo -n "STDERR:${lines}:" > "$MONITOR"
tail --lines=$lines "$STDERR_FILE" > "$MONITOR"
else
for line in "${ERRORS[@]}"; do
echo "ERROR:$line" > "$MONITOR"
done
fi
}
log_error() {
ERRORS+=("$@")
ERRORS+=("$*")
echo "ERROR: $@" | tee $RESULT >&2
report_error
exit 1
}
......@@ -70,18 +87,9 @@ report_task_end() {
echo "$MSG_TYPE_TASK_END:${PROGNAME:2}" > "$MONITOR"
}
report_error() {
if [ ${#ERRORS[*]} -eq 0 ]; then
# No error message. Print stderr
local lines=$(tail --lines=${STDERR_LINE_SIZE} "$STDERR_FILE" | wc -l)
echo -n "STDERR:${lines}:" > "$MONITOR"
tail --lines=$lines "$STDERR_FILE" > "$MONITOR"
else
echo -n "ERROR:" > "$MONITOR"
for line in "${ERRORS[@]}"; do
echo "$line" > "$MONITOR"
done
fi
system_poweroff() {
# Credits to psomas@grnet.gr for this ...
echo o > /proc/sysrq-trigger
}
get_base_distro() {
......@@ -105,7 +113,8 @@ get_base_distro() {
}
get_distro() {
local root_dir=$1
local root_dir distro
root_dir=$1
if [ -e "$root_dir/etc/debian_version" ]; then
distro="debian"
......@@ -137,22 +146,23 @@ get_distro() {
get_partition_table() {
local dev="$1"
local dev output
dev="$1"
# If the partition table is gpt then parted will raise an error if the
# secondary gpt is not it the end of the disk, and a warning that has to
# do with the "Last Usable LBA" entry in gpt.
if ! output="$("$PARTED" -s -m "$dev" unit s print | grep -E -v "^(Warning|Error): ")"; then
log_error "Unable to read partition table for device \`${dev}'"
log_error "Unable to read partition table for device \`${dev}'. The image seems corrupted."
fi
echo "$output"
}
get_partition_table_type() {
local ptable="$1"
local ptable dev field
ptable="$1"
local dev="$(sed -n 2p <<< "$ptable")"
declare -a field
dev="$(sed -n 2p <<< "$ptable")"
IFS=':' read -ra field <<< "$dev"
echo "${field[5]}"
......@@ -190,8 +200,9 @@ is_extended_partition() {
}
get_extended_partition() {
local ptable="$1"
local dev="$(echo "$ptable" | sed -n 2p | cut -d':' -f1)"
local ptable dev
ptable="$1"
dev="$(echo "$ptable" | sed -n 2p | cut -d':' -f1)"
tail -n +3 <<< "$ptable" | while read line; do
part_num=$(cut -d':' -f1 <<< "$line")
......@@ -204,7 +215,8 @@ get_extended_partition() {
}
get_logical_partitions() {
local ptable="$1"
local ptable part_num
ptable="$1"
tail -n +3 <<< "$ptable" | while read line; do
part_num=$(cut -d':' -f1 <<< "$line")
......@@ -217,8 +229,9 @@ get_logical_partitions() {
}
get_last_primary_partition() {
local ptable="$1"
local dev=$(echo "ptable" | sed -n 2p | cut -d':' -f1)
local ptable dev output
ptable="$1"
dev=$(echo "ptable" | sed -n 2p | cut -d':' -f1)
for i in 4 3 2 1; do
if output=$(grep "^$i:" <<< "$ptable"); then
......@@ -230,7 +243,9 @@ get_last_primary_partition() {
}
get_partition_to_resize() {
local dev="$1"
local dev table table_type last_part last_part_num extended last_primary \
ext_num prim_num
dev="$1"
table=$(get_partition_table "$dev")
......@@ -263,7 +278,7 @@ create_partition() {
local part="$2"
local ptype="$3"
declare -a fields
local fields=()
IFS=":;" read -ra fields <<< "$part"
local id="${fields[0]}"
local start="${fields[1]}"
......@@ -280,20 +295,21 @@ create_partition() {
}
enlarge_partition() {
local device="$1"
local part="$2"
local ptype="$3"
local new_end="$4"
local device part ptype new_end fields new_part table logical id
device="$1"
part="$2"
ptype="$3"
new_end="$4"
if [ -z "$new_end" ]; then
new_end=$(cut -d: -f 3 <<< "$(get_last_free_sector "$device")")
fi
declare -a fields
fields=()
IFS=":;" read -ra fields <<< "$part"
fields[2]="$new_end"
local new_part=""
new_part=""
for ((i = 0; i < ${#fields[*]}; i = i + 1)); do
new_part="$new_part":"${fields[$i]}"
done
......@@ -302,8 +318,8 @@ enlarge_partition() {
# If this is an extended partition, removing it will also remove the
# logical partitions it contains. We need to save them for later.
if [ "$ptype" = "extended" ]; then
local table="$(get_partition_table "$device")"
local logical="$(get_logical_partitions "$table")"
table="$(get_partition_table "$device")"
logical="$(get_logical_partitions "$table")"
fi
id=${fields[0]}
......@@ -319,21 +335,35 @@ enlarge_partition() {
}
get_last_free_sector() {
local dev="$1"
local unit="$2"
local dev unit last_line ptype
dev="$1"
unit="$2"
if [ -n "$unit" ]; then
unit="unit $unit"
fi
local last_line="$("$PARTED" -s -m "$dev" "$unit" print free | tail -1)"
local ptype="$(cut -d: -f 5 <<< "$last_line")"
last_line="$($PARTED -s -m "$dev" "$unit" print free | tail -1)"
ptype="$(cut -d: -f 5 <<< "$last_line")"
if [ "$ptype" = "free;" ]; then
echo "$last_line"
fi
}
get_unattend() {
local target exists
target="$1"
# Workaround to search for $target/Unattend.xml in an case insensitive way.
exists=$(find "$target"/ -maxdepth 1 -iname unattend.xml)
if [ $(wc -l <<< "$exists") -gt 1 ]; then
log_error "Found multiple Unattend.xml files in the image:" $exists
fi
echo "$exists"
}
cleanup() {
# if something fails here, it shouldn't call cleanup again...
trap - EXIT
......@@ -367,20 +397,19 @@ cleanup() {
}
task_cleanup() {
rc=$?
local rc=$?
if [ $rc -eq 0 ]; then
report_task_end
else
report_error
fi
cleanup
}
check_if_excluded() {
local name="$(tr [a-z] [A-Z] <<< ${PROGNAME:2})"
local exclude="SNF_IMAGE_PROPERTY_EXCLUDE_TASK_${name}"
local name exclude
name="$(tr [a-z] [A-Z] <<< ${PROGNAME:2})"
exclude="SNF_IMAGE_PROPERTY_EXCLUDE_TASK_${name}"
if [ -n "${!exclude}" ]; then
warn "Task ${PROGNAME:2} was excluded and will not run."
exit 0
......
AC_PREREQ(2.59)
AC_INIT(snf-image-helper, 0.5, synnefo@lists.grnet.gr)
AC_INIT(snf-image-helper, 0.7, synnefo@lists.grnet.gr)
AC_CONFIG_AUX_DIR(autotools)
AC_CONFIG_SRCDIR(configure)
......
......@@ -17,19 +17,30 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
if [ $$ -eq 1 ]; then
mount / -o remount
/etc/init.d/udev start
hwclock -u -s
(exec $0) &
wait
exit 0 # Hopefully this is never called...
fi
. @commondir@/common.sh
set -e
if [ "x$1" != "x--force" ]; then
echo "WARNING: Exiting, this command would cause the system to halt." >&2
echo "Use --force if you know what you're doing." >&2
exit 1
if grep snf_image_activate_helper /proc/cmdline > /dev/null; then
# terminate helper vm when the script exits
add_cleanup system_poweroff
else
log_error "Kernel command line activation flag: " \
"\`snf_image_activate_helper' is missing"
fi
# terminate helper vm when the script exits
add_cleanup telinit 0
if [ ! -b "$FLOPPY_DEV" ]; then
log_error "Floppy device is not present!"
fi
......@@ -53,8 +64,12 @@ fi
if [ -n "$SNF_IMAGE_PROPERTIES" ]; then
properties=$(mktemp --tmpdir properties.XXXXXX)
add_cleanup rm "$properties"
echo "$SNF_IMAGE_PROPERTIES" |
"@scriptsdir@/decode-properties.py" "$properties"
if ! echo "$SNF_IMAGE_PROPERTIES" | \
"@scriptsdir@/decode-properties.py" "$properties"; then
log_error "Unable to decode image properties. " \
"Please check if the variable is in valid json format."
fi
source "$properties"
fi
......@@ -79,6 +94,14 @@ trap '{ umount "$target"; }' ERR
if [ -z "$SNF_IMAGE_PROPERTY_EXCLUDE_ALL_TASKS" ]; then
if [ "$SNF_IMAGE_PROPERTY_OSFAMILY" = "" ]; then
log_error "Required image property \`OSFAMILY' is missing or empty."
fi
if [ "$SNF_IMAGE_PROPERTY_ROOT_PARTITION" = "" ]; then
log_error "Required image property \`ROOT_PARTITION' is missing or empty."
fi
export SNF_IMAGE_RESIZE_PART="$(get_partition_to_resize "$SNF_IMAGE_DEV")"
if [[ ! "$SNF_IMAGE_PROPERTY_OSFAMILY" =~ ^(linux|windows)$ ]]; then
......@@ -90,7 +113,7 @@ if [ -z "$SNF_IMAGE_PROPERTY_EXCLUDE_ALL_TASKS" ]; then
echo "Execute all snf-image tasks...."
$RUN_PARTS -v --exit-on-error "@tasksdir@" 2>&1|
while IFS= read -r line; do
echo $(date +%Y:%m:%d-%H:%M:%S.%N) "$line"
echo $($DATE +%Y:%m:%d-%H:%M:%S.%N) "$line"
done
fi
......
......@@ -41,6 +41,10 @@ if [ -z "$SNF_IMAGE_RESIZE_PART" ]; then
exit 0
fi
if [ -n "$SNF_IMAGE_PROPERTY_DO_SYNC" ]; then
unset EATMYDATA
fi
table=$(get_partition_table "$SNF_IMAGE_DEV")
partition=$(get_partition_by_num "$table" "$SNF_IMAGE_RESIZE_PART")
id=$(cut -d: -f1 <<< "$partition")
......@@ -57,7 +61,7 @@ if [[ "$ptype" == ext[234] ]]; then
# system that has been mounted after the last fs check, but since we are
# sure the file system is clean it's safe enough to bypass this.
if [ "$state" = "clean" ]; then
$RESIZE2FS -f "$device"
$EATMYDATA $RESIZE2FS -f "$device"
else
log_error "The file system state of partition: \`$device' " \
" is not clean (state = $state)"
......
......@@ -34,13 +34,15 @@ if [ ! -d "$SNF_IMAGE_TARGET" ]; then
fi
if [ -z "$SNF_IMAGE_PROPERTY_ROOT_PARTITION" ]; then
log_error "Root Partition image property not defined"
log_error "Required image property \`ROOT_PARTITION' not defined or empty"
fi
rootdev="${SNF_IMAGE_DEV}${SNF_IMAGE_PROPERTY_ROOT_PARTITION}"
if [ ! -b "$rootdev" ]; then
log_error "Image root partition device:\`$rootdev' is not a block device"
log_error "Root partition device:\`$rootdev' is not a block device. " \
"Please check if the value for image property \`ROOT_PARTITION' " \
"(=$SNF_IMAGE_PROPERTY_ROOT_PARTITION) is valid."
fi
mount "$rootdev" "$SNF_IMAGE_TARGET" -o rw
......
......@@ -19,7 +19,7 @@
### BEGIN TASK INFO
# Provides: AddSwap
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: MountImage
# Short-Description: Set up the swap partition and add an entry in fstab
### END TASK INFO
......
......@@ -19,7 +19,7 @@
### BEGIN TASK INFO
# Provides: DeleteSSHKeys
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: MountImage
# Short-Description: Remove ssh keys and in some cases recreate them
### END TASK INFO
......
......@@ -19,16 +19,16 @@
### BEGIN TASK INFO
# Provides: DisableRemoteDesktopConnections
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: MountImage
# Short-Description: Temporary Disable Remote Desktop Connections
### END TASK INFO
#
# This task will change the value of `fDenyTSConnection' registry key located in
# `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\' to
# "true". This will disable RDP connections. The key will change back to "false"
# during the specialize pass of the Windows setup.
# This task will change the value of `fDenyTSConnection' registry key located
# in `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\' to
# "true". This will disable RDP connections. The key will change back to
# "false" during the specialize pass of the Windows setup.
#
set -e
......@@ -48,8 +48,12 @@ if [ "$SNF_IMAGE_PROPERTY_OSFAMILY" != "windows" ]; then
exit 0
fi
# Supress a specific reglookup warning messages. In Windows 2012, although the
# command works correct, it polluts the output with hundreds of warning
# messages about not being able to interprete registry key values.
RGLKP_WRNG="^WARN: While quoting value for '.\+', warning returned: Data could not be interpreted, quoting raw buffer."
hive="$SNF_IMAGE_TARGET/Windows/System32/config/SYSTEM"
current=$($REGLOOKUP "$hive" | grep ^/Select/Current | cut -d, -f3)
current=$($REGLOOKUP "$hive" 2> >(grep -v "$RGLKP_WRNG" >&2) | grep ^/Select/Current | cut -d, -f3)
# Change the key value.
# For a stupid reason chntpw returns 2!
......
......@@ -19,7 +19,7 @@
### BEGIN TASK INFO
# Provides: InstallUnattend
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: MountImage
# Short-Description: Installs Unattend.xml for unattended windows setup
### END TASK INFO
......@@ -45,15 +45,22 @@ fi
target=$SNF_IMAGE_TARGET
mkdir -p "$target/Windows/Setup/Scripts"
if [ -n "$SNF_IMAGE_UNATTEND" ]; then
echo "Installing custom Unattend.xml file..."
if [ -f "$SNF_IMAGE_UNATTEND" ]; then
cat "$SNF_IMAGE_UNATTEND" > "$target/Unattend.xml"
unattend=$(get_unattend "$target")
if [ -n "$unattend" -a -z "$SNF_IMAGE_PROPERTY_USE_DEFAULT_UNATTEND" ]; then
warn "Using the Unattend.xml file found in the image"
else
rm -f "$unattend"
if [ -n "$SNF_IMAGE_UNATTEND" ]; then
echo "Installing custom Unattend.xml file..."
if [ -f "$SNF_IMAGE_UNATTEND" ]; then
cat "$SNF_IMAGE_UNATTEND" > "$target/Unattend.xml"
else
log_error "Custom unattend file: \`"$SNF_IMAGE_UNATTEND"' is missing"
fi
else
log_error "Custom unattend file: \`"$SNF_IMAGE_UNATTEND"' is missing"
cat "@commondir@/unattend.xml" > "$target/Unattend.xml"
fi
else
cat "@commondir@/unattend.xml" > "$target/Unattend.xml"
fi
echo "del /Q /F C:\Unattend.xml" > \
......
......@@ -19,7 +19,7 @@
### BEGIN TASK INFO
# Provides: SELinuxAutorelabel
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: MountImage
# Short-Description: Force the system to relabel at next boot
### END TASK INFO
......
......@@ -19,7 +19,7 @@
### BEGIN TASK INFO
# Provides: AssignHostname
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: InstallUnattend
# Short-Description: Assign Hostname/Computer Name to the instance
### END TASK INFO
......@@ -34,27 +34,34 @@ report_task_start
check_if_excluded
windows_hostname() {
local target="$1"
local password="$2"
local target password unattend tmp_unattend namespace
target="$1"
password="$2"
local tmp_unattend=`mktemp` || exit 1
tmp_unattend=$(mktemp)
add_cleanup rm "$tmp_unattend"
echo -n "Assigning new computer name..."
local namespace="urn:schemas-microsoft-com:unattend"
namespace="urn:schemas-microsoft-com:unattend"
unattend=$(get_unattend "$target")
if [ -z "$unattend" ]; then
log_error "Unattend.xml is missing."
fi
"$XMLSTARLET" ed -N x=$namespace -u "/x:unattend/x:settings/x:component/x:ComputerName" -v "$password" "$target/Unattend.xml" > "$tmp_unattend"
"$XMLSTARLET" ed -N x=$namespace -u "/x:unattend/x:settings/x:component/x:ComputerName" -v "$password" "$unattend" > "$tmp_unattend"
cat "$tmp_unattend" > "$target/Unattend.xml"
cat "$tmp_unattend" > "$unattend"
echo done
}
linux_hostname() {
local target="$1"
local hostname="$2"
local target hostname distro
target="$1"
hostname="$2"
local distro=$(get_base_distro "$target")
distro=$(get_base_distro "$target")
case "$distro" in
debian)
......
......@@ -19,7 +19,7 @@
### BEGIN TASK INFO
# Provides: ChangePassword
# RunBefore: UmountImage
# RunBefore: EnforcePersonality
# RunAfter: InstallUnattend
# Short-Description: Changes Password for specified users
### END TASK INFO
......@@ -34,12 +34,16 @@ report_task_start
check_if_excluded
windows_password() {
local target="$1"
local password="$2"
local target password
target="$1"
password="$2"
echo "@echo off" > "$target/Windows/SnfScripts/ChangeAdminPassword.cmd"
if [ -z "$SNF_IMAGE_PROPERTY_USERS" ]; then
warn "Image property \`USERS' is missing or empty. " \
"Changing the password for default user: \`Administrator'."
SNF_IMAGE_PROPERTY_USERS="Administrator"
fi
......@@ -52,36 +56,35 @@ windows_password() {
}
linux_password() {
local target="$1"
local password="$2"
local target password hash users tmp_shadow
target="$1"
password="$2"
local hash=$("@scriptsdir@/snf-passtohash.py" "$password")
hash=$("@scriptsdir@/snf-passtohash.py" "$password")
if [ ! -e "$target/etc/shadow" ]; then
log_error "No /etc/shadow found!"
fi
declare -a users
users=()
if [ -n "$SNF_IMAGE_PROPERTY_USERS" ]; then
for usr in $SNF_IMAGE_PROPERTY_USERS; do
users+=("$usr")
done
else