# Indirectly call a function named by ${1}_${2}
call_func () {
- local func="$1" ; shift
- local type="$1" ; shift
+ local __func="$1" ; shift
+ local __type="$1" ; shift
- local f="${func}_${type}"
+ local f="${__func}_${__type}"
if type -t "$f" >/dev/null && ! type -P "$f" >/dev/null ; then
"$f" "$@"
else
- f="${func}_DEFAULT"
+ f="${__func}_DEFAULT"
if type -t "$f" >/dev/null && ! type -P "$f" >/dev/null ; then
- "$f" "$type" "$@"
+ "$f" "$__type" "$@"
else
- die "No function defined for \"${func}\" \"${type}\""
+ die "No function defined for \"${__func}\" \"${__type}\""
fi
fi
}
local disk="$1"
local type="$2"
- mount_disk "$disk"
+ diskimage_mount "$disk"
setup_base "$type"
- unmount_disk
+ diskimage_unmount
}
# Provides an easy way of removing nodes from $NODE.
IPNUM=$FIRSTIP
CLUSTER="base"
- mount_disk $DISK
+ diskimage_mount $DISK
setup_base
- unmount_disk
+ diskimage_unmount
UUID=`uuidgen`
MAC6="${mac_prefix}06"
}
-# mount a qemu image via nbd
-connect_nbd() {
- echo "Connecting nbd to $1"
- mkdir -p mnt
- modprobe nbd
- killall -9 -q $QEMU_NBD || true
- $QEMU_NBD -p 1300 $1 &
- sleep 1
- [ -r $NBD_DEVICE ] || {
- mknod $NBD_DEVICE b 43 0
- }
- umount mnt 2> /dev/null || true
- nbd-client -d $NBD_DEVICE > /dev/null 2>&1 || true
- killall -9 -q nbd-client || true
- nbd-client localhost 1300 $NBD_DEVICE > /dev/null 2>&1 || true &
- sleep 1
-}
+######################################################################
-# disconnect nbd
-disconnect_nbd() {
- echo "Disconnecting nbd"
- sync; sync
- nbd-client -d $NBD_DEVICE > /dev/null 2>&1 || true
- killall -9 -q nbd-client || true
- killall -q $QEMU_NBD || true
-}
+# Updating a disk image...
-setup_image ()
+make_system_disk_access_function ()
{
- local disk="$1"
-
- case "$SYSTEM_DISK_FORMAT" in
- qcow2)
- connect_nbd "$disk"
- device=$NBD_DEVICE
- extra_mount_options=""
- ;;
- raw|reflink)
- device="$disk"
- extra_mount_options=",loop"
- ;;
- *)
- die "Error: unknown SYSTEM_DISK_FORMAT=${SYSTEM_DISK_FORMAT}."
- esac
+ eval "$1 () { call_func $1 \"\$SYSTEM_DISK_ACCESS_METHOD\" \"\$@\" ; }"
}
-cleanup_image ()
-{
- case "$SYSTEM_DISK_FORMAT" in
- qcow2)
- disconnect_nbd
- ;;
- raw|reflink)
- :
- ;;
- *)
- die "Error: unknown SYSTEM_DISK_FORMAT=${SYSTEM_DISK_FORMAT}."
- esac
-}
-
-# mount a qemu image via nbd
-mount_disk()
-{
- local disk="$1"
-
- local device extra_mount_options
-
- setup_image "$disk"
-
- echo "Mounting disk ${disk}..."
- local m o
- for m in $SYSTEM_DISK_MOUNTS ; do
- local mount_ok=0
- o="${m#*:}" # Offset is after colon
- m="${m%:*}" # Mountpoint is before colon
- echo " mount ${m} from offset ${o}"
- local i
- for i in $(seq 1 5); do
- mount -o offset=${o}${extra_mount_options} $device "mnt${m}" && {
- mount_ok=1
- break
- }
- umount mnt 2>/dev/null || true
- sleep 1
- done
- [ $mount_ok = 1 ] || die "Failed to mount $disk"
- done
-
- [ -d mnt/root ] || {
- echo "Mounted directory does not look like a root filesystem"
- ls -latr mnt
- exit 1
- }
-}
-
-# unmount a qemu image
-unmount_disk() {
- echo "Unmounting disk"
- sync; sync;
-
- # umounts are done in reverse. Be lazy and construct a reverse
- # list, since the shell will handle any strange whitespace for
- # us... ;-)
- local umounts=""
- local m
- for m in $SYSTEM_DISK_MOUNTS ; do
- umounts="${m%:*}${umounts:+ }${umounts}"
- done
- for m in $umounts ; do
- echo " umount ${m}"
- umount "mnt${m}" || umount "mnt${m}" || true
- done
- cleanup_image
-}
+for i in \
+ mount unmount \
+ mkdir_p substitute_vars chmod chmod_reference \
+ is_directory append_text_file append_text sed put ln_s command \
+ ; do
+ make_system_disk_access_function "diskimage_$i"
+done
# setup the files from $BASE_TEMPLATES/, substituting any variables
# based on the config
local f
for f in $(cd "$d" && find . \! -name '*~') ; do
+ f="${f#./}" # remove leading "./" for clarity
if [ -d "$d/$f" ]; then
- mkdir -p mnt/"$f"
+ diskimage_mkdir_p "/$f"
else
- substitute_vars "$d/$f" "mnt/$f"
+ diskimage_substitute_vars "$d/$f" "/$f"
fi
- chmod --reference="$d/$f" "mnt/$f"
+ diskimage_chmod_reference "$d/$f" "/$f"
done
}
{
# this is needed as git doesn't store file permissions other
# than execute
- chmod 600 mnt/etc/ssh/*key mnt/root/.ssh/*
- chmod 700 mnt/etc/ssh mnt/root/.ssh mnt/root
+ # Note that we protect the wildcards from the local shell.
+ diskimage_chmod 600 "/etc/ssh/*key" "/root/.ssh/*"
+ diskimage_chmod 700 "/etc/ssh" "/root/.ssh" "/root"
if [ -r "$HOME/.ssh/id_rsa.pub" ]; then
echo "Adding $HOME/.ssh/id_rsa.pub to ssh authorized_keys"
- cat "$HOME/.ssh/id_rsa.pub" >> mnt/root/.ssh/authorized_keys
+ diskimage_append_text_file "$HOME/.ssh/id_rsa.pub" "/root/.ssh/authorized_keys"
fi
if [ -r "$HOME/.ssh/id_dsa.pub" ]; then
echo "Adding $HOME/.ssh/id_dsa.pub to ssh authorized_keys"
- cat "$HOME/.ssh/id_dsa.pub" >> mnt/root/.ssh/authorized_keys
+ diskimage_append_text_file "$HOME/.ssh/id_dsa.pub" "/root/.ssh/authorized_keys"
fi
}
{
echo "Adjusting grub.conf"
local o="$EXTRA_KERNEL_OPTIONS" # For readability.
- sed -e "s/console=ttyS0,19200/console=ttyS0,115200/" \
+ diskimage_sed "/boot/grub/grub.conf" \
+ -e "s/console=ttyS0,19200/console=ttyS0,115200/" \
-e "s/ nodmraid//" -e "s/ nompath//" \
- -e "s/quiet/noapic divider=10${o:+ }${o}/g" mnt/boot/grub/grub.conf -i.org
+ -e "s/quiet/noapic divider=10${o:+ }${o}/g"
}
register_hook setup_base_hooks setup_base_grub_conf
fi
echo "Setting up networks"
- cat $hosts_file >>mnt/etc/hosts
+ diskimage_append_text_file "$hosts_file" "/etc/hosts"
echo "Setting up /etc/ctdb/nodes"
- mkdir -p mnt/etc/ctdb
- cp $nodes_file mnt/etc/ctdb/nodes
+ diskimage_mkdir_p "/etc/ctdb"
+ diskimage_put "$nodes_file" "/etc/ctdb/nodes"
[ "$WEBPROXY" = "" ] || {
- echo "export http_proxy=$WEBPROXY" >> mnt/etc/bashrc
+ diskimage_append_text "export http_proxy=$WEBPROXY" "/etc/bashrc"
}
if [ -n "$NFSSHARE" -a -n "$NFS_MOUNTPOINT" ] ; then
echo "Enabling nfs mount of $NFSSHARE"
- mkdir -p "mnt$NFS_MOUNTPOINT"
- echo "$NFSSHARE $NFS_MOUNTPOINT nfs intr" >> mnt/etc/fstab
+ diskimage_mkdir_p "$NFS_MOUNTPOINT"
+ diskimage_append_text "$NFSSHARE $NFS_MOUNTPOINT nfs intr" "/etc/fstab"
fi
- mkdir -p mnt/etc/yum.repos.d
- echo '@@@YUM_TEMPLATE@@@' | substitute_vars - > mnt/etc/yum.repos.d/autocluster.repo
+ diskimage_mkdir_p "/etc/yum.repos.d"
+ echo '@@@YUM_TEMPLATE@@@' | diskimage_substitute_vars - "/etc/yum.repos.d/autocluster.repo"
}
register_hook setup_base_hooks setup_network
;;
mount)
[ $# != 1 ] && usage
- mount_disk "$1"
+ diskimage_mount "$1"
;;
unmount)
[ $# != 0 ] && usage
- unmount_disk
+ diskimage_unmount
;;
bootbase)
boot_base;
--- /dev/null
+# Hey Emacs, this is a -*- shell-script -*- !!!
+
+# This file provides functions to implement loopback mounting and
+# access/update of disk images, either via qemu-nbd/nbd (for qcow2
+# images) or via loopback (for raw (or reflink) images).
+
+######################################################################
+
+diskimage_mount_loopback ()
+{
+ local disk="$1"
+
+ local device extra_mount_options
+
+ _setup_image "$disk"
+
+ echo "Mounting disk ${disk}..."
+ local m o
+ for m in $SYSTEM_DISK_MOUNTS ; do
+ local mount_ok=0
+ o="${m#*:}" # Offset is after colon
+ m="${m%:*}" # Mountpoint is before colon
+ echo " mount ${m} from offset ${o}"
+ local i
+ for i in $(seq 1 5); do
+ mount -o offset=${o}${extra_mount_options} $device "mnt${m}" && {
+ mount_ok=1
+ break
+ }
+ umount mnt 2>/dev/null || true
+ sleep 1
+ done
+ [ $mount_ok = 1 ] || die "Failed to mount $disk"
+ done
+
+ [ -d "$mnt/root" ] || {
+ echo "Mounted directory does not look like a root filesystem"
+ ls -latr mnt
+ exit 1
+ }
+}
+
+# unmount a qemu image
+diskimage_unmount_loopback ()
+{
+ echo "Unmounting disk"
+ sync; sync;
+
+ # umounts are done in reverse. Be lazy and construct a reverse
+ # list, since the shell will handle any strange whitespace for
+ # us... ;-)
+ local umounts=""
+ local m
+ for m in $SYSTEM_DISK_MOUNTS ; do
+ umounts="${m%:*}${umounts:+ }${umounts}"
+ done
+ for m in $umounts ; do
+ echo " umount ${m}"
+ umount "mnt${m}" || umount "mnt${m}" || true
+ done
+ _cleanup_image
+}
+
+diskimage_mkdir_p_loopback ()
+{
+ mkdir -p "mnt$1"
+}
+
+diskimage_substitute_vars_loopback ()
+{
+ substitute_vars "$1" "mnt$2"
+}
+
+diskimage_chmod_loopback ()
+{
+ local mode="$1" ; shift
+ local i
+ for i ; do
+ # this should handle wildcards
+ eval chmod "$mode" "mnt$i"
+ done
+}
+
+diskimage_chmod_reference_loopback ()
+{
+ local ref="$1" ; shift
+ local i
+ for i ; do
+ # this should handle wildcards
+ eval chmod --reference="$ref" "mnt$i"
+ done
+}
+
+diskimage_is_directory_loopback ()
+{
+ [ -d "mnt$1" ]
+}
+
+diskimage_append_text_file_loopback ()
+{
+ cat "$1" >> "mnt$2"
+}
+
+diskimage_append_text_loopback ()
+{
+ echo "$1" >> "mnt$2"
+}
+
+diskimage_sed_loopback ()
+{
+ local file="$1" ; shift
+ sed -i.org "$@" "mnt$file"
+}
+
+diskimage_put_loopback ()
+{
+ cp "$1" "mnt$2"
+}
+
+diskimage_ln_s_loopback ()
+{
+ ln -s "$1" "mnt$2"
+}
+
+diskimage_command_loopback ()
+{
+ chroot mnt "$@"
+}
+
+######################################################################
+
+# Private functions
+
+# mount a qemu image via nbd
+_connect_nbd() {
+ echo "Connecting nbd to $1"
+ mkdir -p mnt
+ modprobe nbd
+ killall -9 -q $QEMU_NBD || true
+ $QEMU_NBD -p 1300 $1 &
+ sleep 1
+ [ -r $NBD_DEVICE ] || {
+ mknod $NBD_DEVICE b 43 0
+ }
+ umount mnt 2> /dev/null || true
+ nbd-client -d $NBD_DEVICE > /dev/null 2>&1 || true
+ killall -9 -q nbd-client || true
+ nbd-client localhost 1300 $NBD_DEVICE > /dev/null 2>&1 || true &
+ sleep 1
+}
+
+# disconnect nbd
+_disconnect_nbd() {
+ echo "Disconnecting nbd"
+ sync; sync
+ nbd-client -d $NBD_DEVICE > /dev/null 2>&1 || true
+ killall -9 -q nbd-client || true
+ killall -q $QEMU_NBD || true
+}
+
+_setup_image ()
+{
+ local disk="$1"
+
+ case "$SYSTEM_DISK_FORMAT" in
+ qcow2)
+ _connect_nbd "$disk"
+ device=$NBD_DEVICE
+ extra_mount_options=""
+ ;;
+ raw|reflink)
+ device="$disk"
+ extra_mount_options=",loop"
+ ;;
+ *)
+ die "Error: unknown SYSTEM_DISK_FORMAT=${SYSTEM_DISK_FORMAT}."
+ esac
+}
+
+_cleanup_image ()
+{
+ case "$SYSTEM_DISK_FORMAT" in
+ qcow2)
+ _disconnect_nbd
+ ;;
+ raw|reflink)
+ :
+ ;;
+ *)
+ die "Error: unknown SYSTEM_DISK_FORMAT=${SYSTEM_DISK_FORMAT}."
+ esac
+}
+
local idir="/var/lib/iscsi"
local dd="${idir}/nodes/${ISCSI_IQN}.${CLUSTER}:tgtd/${ISCSI_HOST},${ISCSI_PORT},1"
- local d="mnt${dd}/default"
- mkdir -p "mnt${dd}"
- substitute_vars "$ISCSI_DEFAULT_TEMPLATE" "$d"
- chmod 600 "$d"
+ local d="${dd}/default"
+ diskimage_mkdir_p "${dd}"
+ diskimage_substitute_vars "$ISCSI_DEFAULT_TEMPLATE" "$d"
+ diskimage_chmod 600 "$d"
local sd="${idir}/send_targets/${ISCSI_HOST},${ISCSI_PORT}"
- local s="mnt${sd}/st_config"
- mkdir -p "mnt${sd}"
- substitute_vars "$ISCSI_ST_CONFIG_TEMPLATE" "$s"
- chmod 600 "$s"
+ local s="${sd}/st_config"
+ diskimage_mkdir_p "${sd}"
+ diskimage_substitute_vars "$ISCSI_ST_CONFIG_TEMPLATE" "$s"
+ diskimage_chmod 600 "$s"
- ln -s "$dd" "mnt/${sd}/${ISCSI_IQN}.${ISCSI_IQN}.${CLUSTER}:tgtd,${ISCSI_HOST},${ISCSI_PORT},1,default"
+ diskimage_ln_s "$dd" "/${sd}/${ISCSI_IQN}.${ISCSI_IQN}.${CLUSTER}:tgtd,${ISCSI_HOST},${ISCSI_PORT},1,default"
# After the iscsi initscript is run, new devices for multipath
# don't seem to be noticed anymore. This enables an initscript
# that ensures that multipath is run when the desired number of
# shared disk paths are available.
- chroot mnt /sbin/chkconfig --add iscsimultipath
+ diskimage_command /sbin/chkconfig --add iscsimultipath
local ip_addr=$(shared_disk_iscsi_setup_base_get_ip)
cat <<EOF >>"$iscsi_out"