Abstract out qemu-nbd/NBD/loopback mount of disk image.
authorMartin Schwenke <martin@meltin.net>
Wed, 9 Feb 2011 04:04:21 +0000 (15:04 +1100)
committerMartin Schwenke <martin@meltin.net>
Thu, 10 Feb 2011 05:11:17 +0000 (16:11 +1100)
In preparation for adding an alternate method.

Signed-off-by: Martin Schwenke <martin@meltin.net>
autocluster
config.d/00base.defconf
config.d/05_diskimage_loopback.defconf [new file with mode: 0644]
config.d/10shareddisk.defconf

index a86a20b59d6fa05fc6e965f21ef6ecd54a0873ea..4ce31a79835b1c3d1e7fbe764b03c3ed8c05c451 100755 (executable)
@@ -93,18 +93,18 @@ die () {
 
 # 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
 }
@@ -236,9 +236,9 @@ create_node_configure_image ()
     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.
@@ -575,9 +575,9 @@ boot_base() {
     IPNUM=$FIRSTIP
     CLUSTER="base"
 
-    mount_disk $DISK
+    diskimage_mount $DISK
     setup_base
-    unmount_disk
+    diskimage_unmount
 
     UUID=`uuidgen`
     
@@ -610,120 +610,22 @@ set_macaddrs () {
     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
@@ -736,12 +638,13 @@ copy_base_dir_substitute_templates ()
 
     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
 }
 
@@ -751,15 +654,16 @@ setup_base_ssh_keys ()
 {
     # 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
 }
 
@@ -769,9 +673,10 @@ setup_base_grub_conf ()
 {
     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
@@ -800,24 +705,24 @@ setup_network()
     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
@@ -1307,11 +1212,11 @@ case $command in
        ;;
     mount)
        [ $# != 1 ] && usage
-       mount_disk "$1"
+       diskimage_mount "$1"
        ;;
     unmount)
        [ $# != 0 ] && usage
-       unmount_disk
+       diskimage_unmount
        ;;
     bootbase)
        boot_base;
index a1cc0369846bfbb9bdeb86ce8816202b9c5b48aa..a019fd568609d66439767d965440c5e1f0bcad37 100644 (file)
@@ -105,6 +105,9 @@ defconf SYSTEM_DISK_CACHE "writeback" \
 defconf SYSTEM_DISK_FORMAT "qcow2" \
        "qcow2|raw|reflink|none" "system disk image format"
 
+defconf SYSTEM_DISK_ACCESS_METHOD "loopback" \
+       "loopback" "how to setup up disk images"
+
 system_disk_mounts ()
 {
     case "$RHEL_VERSION" in
diff --git a/config.d/05_diskimage_loopback.defconf b/config.d/05_diskimage_loopback.defconf
new file mode 100644 (file)
index 0000000..421d32e
--- /dev/null
@@ -0,0 +1,193 @@
+# 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
+}
+
index b1a48004276e4da2c11be4dcbc6d1d39a6ac9434..96d16d9cd584aec75cd8ab0992c41350dc9b0fb2 100644 (file)
@@ -177,24 +177,24 @@ shared_disk_iscsi_setup_base_internal ()
     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"