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

Merge branch 'master' into xen

Conflicts:
	snf-image-helper/common.sh
	snf-image-host/Makefile.am
	snf-image-host/common.sh.in
	snf-image-host/create
	snf-image-host/defaults
parents fcae4e91 56e4f945
2013-01-21, v0.7.6
* Mount /proc and /dev before chrooting
* Fix a bug in DeleteSSHKeys task where the code for checking for
non-default keys was never called.
2013-01-17, v0.7.5
2013-01-08, v0.7.4
* Fix a bug in the code that determines which partition to resize
* On linux images, mount all local partition during deployment. Not
just /.
2013-01-04, v0.7.3
2013-01-04, v0.7.2
* In windows images make sure the file C:\Window\panther\Unattend.xml
gets removed after sysprep runs
* Support extended partitions with id 0x0f
* Fix a bug in the error monitoring system
* Fix a bug in AssignHostname for archlinux images
* In AssignHostname check for the presence of /etc/hostname before
trying to determine the disto of a Linux image.
2012-12-07, v0.7.1
* Fix a race condition where in some cases could lead to a kernel
panic for the helper VM.
2012-12-03, v0.7
* 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
......
......@@ -31,6 +31,8 @@ BLKID=blkid
BLOCKDEV=blockdev
REGLOOKUP=reglookup
CHNTPW=chntpw
DATE="date -u" # Time in UTC
EATMYDATA=eatmydata
CLEANUP=( )
ERRORS=( )
......@@ -94,11 +96,30 @@ prepare_helper() {
export RESULT_FD MONITOR_FD
}
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_FD}
tail --lines=$lines "$STDERR_FILE" >&${MONITOR_FD}
else
for line in "${ERRORS[@]}"; do
echo "ERROR:$line" >&${MONITOR_FD}
done
fi
}
log_error() {
ERRORS+=("$@")
ERRORS+=("$*")
echo "ERROR: $@" >&2
echo "ERROR: $@" >&${MONITOR_FD}
exit 1
echo "ERROR: $@" >&${MONITOR_FD}
echo "ERROR" >&${RUSULT_FD}
# Use return instead of exit. The set -x options will terminate the script
# but will also trigger ERR traps if defined.
return 1
}
warn() {
......@@ -114,17 +135,12 @@ report_task_end() {
echo "$MSG_TYPE_TASK_END:${PROGNAME:2}" >&${MONITOR_FD}
}
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_FD}
tail --lines=$lines "$STDERR_FILE" >&${MONITOR_FD}
else
for line in "${ERRORS[@]}"; do
echo "ERROR:$line" >&${MONITOR_FD}
done
fi
system_poweroff() {
while [ 1 ]; do
# Credits to psomas@grnet.gr for this ...
echo o > /proc/sysrq-trigger
sleep 1
done
}
get_base_distro() {
......@@ -148,7 +164,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"
......@@ -180,22 +197,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]}"
......@@ -225,7 +243,7 @@ is_extended_partition() {
local part_num="$2"
id=$($SFDISK --print-id "$dev" "$part_num")
if [ "$id" = "5" ]; then
if [ "$id" = "5" -o "$id" = "f" ]; then
echo "yes"
else
echo "no"
......@@ -233,8 +251,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")
......@@ -247,7 +266,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")
......@@ -260,8 +280,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
......@@ -273,7 +294,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")
......@@ -289,7 +312,7 @@ get_partition_to_resize() {
extended=$(get_extended_partition "$table")
last_primary=$(get_last_primary_partition "$table")
ext_num=$(cut -d: -f1 <<< "$extended")
prim_num=$(cut -d: -f1 <<< "$last_primary")
last_prim_num=$(cut -d: -f1 <<< "$last_primary")
if [ "$ext_num" != "$last_prim_num" ]; then
echo "$last_prim_num"
......@@ -306,7 +329,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]}"
......@@ -323,20 +346,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
......@@ -345,8 +369,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]}
......@@ -362,21 +386,47 @@ 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"
}
umount_all() {
local target mpoints
target="$1"
# Unmount file systems mounted under directory `target'
mpoints="$({ awk "{ if (match(\$2, \"^$target\")) { print \$2 } }" < /proc/mounts; } | sort -rbd | uniq)"
for mpoint in $mpoints; do
umount $mpoint
done
}
cleanup() {
# if something fails here, it shouldn't call cleanup again...
trap - EXIT
......@@ -410,7 +460,7 @@ cleanup() {
}
task_cleanup() {
rc=$?
local rc=$?
if [ $rc -eq 0 ]; then
report_task_end
......@@ -422,8 +472,9 @@ task_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.6, synnefo@lists.grnet.gr)
AC_CONFIG_AUX_DIR(autotools)
AC_CONFIG_SRCDIR(configure)
......
......@@ -17,18 +17,34 @@
# 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
fi
# Enable errtrace to make functions inherit the ERR trap
set -o errtrace
trap report_error ERR
# terminate helper vm when the script exits
add_cleanup telinit 0
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
prepare_helper
......@@ -55,8 +71,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
......@@ -75,29 +95,39 @@ if [ -z "$RUN_PARTS" ]; then
log_error "run-parts program is missing from the system"
fi
# If something goes wrong with the tasks, try to umount the target filesystem
# in case it is left mounted...
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
log_error "Supported values for OSFAMILY property are: linux|windows"
fi
# If something goes wrong with the tasks, try to umount the disk file
# systems that are still mounted.
trap '{ umount_all "$target"; }' ERR
# Redirect standard error to standard output,
# prepend a timestamp before each line of output.
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"
while read -r line; do
echo $($DATE +%Y:%m:%d-%H:%M:%S.%N) "$line"
done
# Reset the handler to its original value
trap report_error ERR
fi
# Disable the trap. If code reaches here, the filesystem is unmounted.
trap - ERR
return_success
......
......@@ -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,17 +34,49 @@ 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
if [ "$SNF_IMAGE_PROPERTY_OSFAMILY" != "linux" ]; then
exit 0
fi
if [ ! -f "${SNF_IMAGE_TARGET}/etc/fstab" ]; then
log_error "/etc/fstab is missing from the root file system"
fi
# Read the local partitions from fstab and get a sorted list:
#<mount_point> <device> <options>
fstab="$(grep -v ^\# "${SNF_IMAGE_TARGET}/etc/fstab" | awk '{ if (match($3, "ext[234]")) { print $2,$1,$4 } }' | sort -bd)"
# Mount non-root filesystems
while read line; do
read -ra entry <<< "$line"
# Skip root. It is already mounted
if [ "${entry[0]}" = "/" ]; then
continue
fi
if [[ ${entry[1]} =~ ^(LABEL|UUID)= ]]; then
entry[1]=$(findfs "${entry[1]}")
fi
# I'm in doupt. Sould I mount the filesystems with the mount options
# found in the image's /etc/fstab or not?
mount "${entry[1]}" "${SNF_IMAGE_TARGET}${entry[0]}" # -o "${entry[2]}"
done <<< "$fstab"
exit 0
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
......@@ -50,6 +50,11 @@ ECDSA_KEY="/etc/ssh/ssh_host_ecdsa_key"
target="$SNF_IMAGE_TARGET"
mount -o bind /proc "$target/proc"
add_cleanup umount "$target/proc"
mount -o bind /dev "$target/dev"
add_cleanup umount "$target/dev"
#Remove the default keys
for pair in "$HOST_KEY@rsa1" "$RSA_KEY@rsa" "$DSA_KEY@dsa" "$ECDSA_KEY@ecdsa"; do
key=$(echo $pair | cut -d@ -f1)
......@@ -72,24 +77,24 @@ if [ ! -e "$config" ]; then
fi
# Remove non-default keys...
grep ^HostKey "$config" || true | while read key_line; do
{ grep ^HostKey "$config" || true; } | while read key_line; do
key=$(echo $key_line | cut -d" " -f2)
if [ "$key" = $HOST_KEY -o "$key" = $RSA_KEY -o \
"$key" = $DSA_KEY -o "$key" = $ECDSA_KEY ]; then
continue;
continue
fi
if [ "x$distro" = "xdebian" ]; then
# Most distros recreate missing keys...debian complains
type=""
if [ -e "$target/$key" ]; then
if grep -e "-----BEGIN DSA PRIVATE KEY-----" "$target/$key"; then
if grep -e "-----BEGIN DSA PRIVATE KEY-----" "$target/$key" > /dev/null; then
type=dsa
elif grep -e "-----BEGIN EC PRIVATE KEY-----" "$target/$key"; then
elif grep -e "-----BEGIN EC PRIVATE KEY-----" "$target/$key" > /dev/null; then
type=ecdsa
elif grep -e "-----BEGIN RSA PRIVATE KEY-----" "$target/$key"; then
elif grep -e "-----BEGIN RSA PRIVATE KEY-----" "$target/$key" > /dev/null; then
type=rsa
elif grep -e "SSH PRIVATE KEY FILE FORMAT" "$target/$key"; then
elif grep -e "SSH PRIVATE KEY FILE FORMAT" "$target/$key" > /dev/null; then
type=rsa1
fi
else # do some guessing...
......
......@@ -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!
......
......@@ -45,18 +45,28 @@ 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"