[Ovirt-devel] [PATCH node] Added support for local storage configuration.

Jim Meyering jim at meyering.net
Fri Nov 14 11:23:13 UTC 2008


"Darryl L. Pierce" <dpierce at redhat.com> wrote:
> This patch wipes out the entire disk on the node and replaces it with
> a set of partitions. The partitions are a raw partition to hold the bootable
> kernel, and the rest of the disk is taken up as an physical volume.
>
> On the physical volume is created the following logical volumes:
>
>  * SWAP    - swap partition
>  * ROOT    - to host the node image
>  * CONFIG  - to hold node configuration data
>  * LOGGING - to hold local logs
>  * DATA    - to hold VM images
>
> Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
> ---
>  scripts/ovirt-config-storage |  199 ++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 199 insertions(+), 0 deletions(-)
>
> diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage
> index c856ef1..25962e1 100755
> --- a/scripts/ovirt-config-storage
> +++ b/scripts/ovirt-config-storage
> @@ -1,2 +1,201 @@
>  #!/bin/bash
>  #
> +# To automate the partitioning, pass in the specific fields in this order
> +# ovirt-config-storage [swap size] [boot size] [root size] [logging size]
> +#
> +# All sizes are in megabytes
> +#
> +
> +function do_resolve_sizes
> +{
> +    DATA_SIZE=$(echo "scale=0; ($SPACE - $BOOT_SIZE - $SWAP_SIZE - $ROOT_SIZE - $CONFIG_SIZE - $LOGGING_SIZE)" | bc -l)
> +}
> +
> +function do_configure
> +{
> +    read -p "Swap partition size (Currently ${SWAP_SIZE} MB)? "
> +    if [[ $REPLY =~ ^[0-9]+$ ]] && [[ $REPLY -gt 0 ]]; then
> +        SWAP_SIZE=$REPLY
> +    else
> +        printf "Swap value is invalid: retaining ${SWAP_SIZE} MB.\n"
> +    fi
> +
> +    read -p "Boot partition size (Currently ${BOOT_SIZE} MB)? "
> +    if [[ $REPLY =~ ^[0-9]+$ ]] && [[ $REPLY -gt 0 ]]; then
> +        BOOT_SIZE=$REPLY
> +    else
> +        printf "Boot value is invalid: retaining ${BOOT_SIZE}.\n"
> +    fi
> +
> +    read -p "Root partition size (Current ${ROOT_SIZE} MB)? "
> +    if [[ $REPLY =~ ^[0-9]+$ ]] && [[ $REPLY -gt 0 ]]; then
> +        ROOT_SIZE=$REPLY
> +    else
> +        printf "Install size is invalid: retaining ${ROOT_SIZE} MB.\n"
> +    fi
> +
> +    read -p "Logging partition size (Current ${LOGGING_SIZE} MB)? "
> +    if [[ $REPLY =~ ^[0-9]+$ ]] && [[ $REPLY -gt 0 ]]; then
> +        LOGGING_SIZE=$REPLY
> +    else
> +        printf "Install size is invalid: retaining ${LOGGING_SIZE} MB.\n"
> +    fi
> +
> +    do_resolve_sizes
> +}

Please replace the above function with the following equivalent one:
(except that it doesn't say "Install size" for invalid _Logging_ size)

function do_configure
{
    for i in swap boot root logging; do
	uc=$(echo $i|tr '[[:lower:]]' '[[:upper:]]')
	var=${uc}_SIZE
	eval "size=\$$var"
	read -p "$i partition size (Currently $size MB)? "
	if [[ $REPLY =~ ^[0-9]+$ ]] && [[ $REPLY -gt 0 ]]; then
	    eval "$var=$REPLY"
	else
	    printf "invalid value: '$i'.  retaining $size MB.\n"
	fi
    done

    do_resolve_sizes
}


> +function do_review
> +{
> +    printf "\n"
> +    printf "The local disk will be repartitioned as follows:\n"
> +    printf "================================================\n"
> +    printf "           Physical Hard Disk: ${DRIVE}\n"
> +    printf "      Total storage available: ${SPACE} MB\n"
> +    printf "          Swap partition size: ${SWAP_SIZE} MB\n"
> +    printf "          Boot partition size: ${BOOT_SIZE} MB\n"
> +    printf "  Installation partition size: ${ROOT_SIZE} MB\n"
> +    printf " Configuration partition size: ${CONFIG_SIZE} MB\n"
> +    printf "       Logging partition size: ${LOGGING_SIZE} MB\n"
> +    printf "          Data partition size: ${DATA_SIZE} MB\n"
> +    printf "\n"
> +}

You can get away with a lot less "syntax" (ease readability/maint)
like this:

function do_review
{
    cat <<EOF

The local disk will be repartitioned as follows:
================================================
           Physical Hard Disk: $DRIVE
      Total storage available: $SPACE MB
          Swap partition size: $SWAP_SIZE MB
          Boot partition size: $BOOT_SIZE MB
  Installation partition size: $ROOT_SIZE MB
 Configuration partition size: $CONFIG_SIZE MB
       Logging partition size: $LOGGING_SIZE MB
          Data partition size: $DATA_SIZE MB

EOF
}

> +
> +function perform_partitioning
> +{
> +    printf "Preparing local storage. Please wait..."
> +
> +    {

How about putting "set -e" here.
Then if there's any failure, the whole script fails.

> +    vgroups=$(vgdisplay -C | awk '{ print $1" "; }')
> +    vgremove -f $vgroups
> +
> +    dd if=/dev/zero of=$DRIVE bs=1K count=1
> +    blockdev --rereadpt $DRIVE
> +    partprobe -s $DRIVE
> +
> +    parted $DRIVE -s "mklabel gpt"
> +    parted $DRIVE -s "mkpart primary ext2 0M ${BOOT_SIZE}M"
> +    parted $DRIVE -s "mkpart primary ext2 ${BOOT_SIZE}M ${SPACE}M"
> +    parted $DRIVE -s "set 2 lvm on"
> +
> +    pvcreate "${DRIVE}2"
> +    pvck
> +    vgcreate /dev/HostVG "${DRIVE}2"
> +
> +    lvcreate --name Swap    --size ${SWAP_SIZE}M    /dev/HostVG
> +    lvcreate --name Root    --size ${ROOT_SIZE}M    /dev/HostVG
> +    lvcreate --name Config  --size ${CONFIG_SIZE}M  /dev/HostVG
> +    lvcreate --name Logging --size ${LOGGING_SIZE}M /dev/HostVG
> +    lvcreate --name Data    -l 100%FREE             /dev/HostVG
> +
> +    mke2fs -j -T ext2 "${DRIVE}1"         -L "BOOT"
> +    tune2fs -c 0 -i 0 "${DRIVE}1"
> +    mkswap /dev/HostVG/Swap
> +    mke2fs -j -T ext2 /dev/HostVG/Root    -L "ROOT"

Per discussion with Alan Pevec on IRC, it looks like those two above
should both be "-T ext3" rather than "-j T ext2".  Slightly clearer.
And the following don't need -j.  You get the journal
with "ext3" by default.

> +    tune2fs -c 0 -i 0 /dev/HostVG/Root
> +    mke2fs -j -T ext3 /dev/HostVG/Config  -L "CONFIG"
> +    tune2fs -c 0 -i 0 /dev/HostVG/Config
> +    mke2fs -j -T ext3 /dev/HostVG/Logging -L "LOGGING"
> +    tune2fs -c 0 -i 0 /dev/HostVG/Logging
> +    mke2fs -j -T ext3 /dev/HostVG/Data    -L "DATA"
> +    tune2fs -c 0 -i 0 /dev/HostVG/Data
> +    } > /var/log/ovirt-partition.log 2>&1
> +
> +    printf "Completed!\n\n"
> +}
> +
> +function do_confirm
> +{
> +    while true; do
> +        printf "\n"
> +        printf "!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!\n"
> +        printf "!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!\n"
> +        printf "!!WARNING!!                                                                               !!WARNING!!\n"
> +        printf "!!WARNING!!                                                                               !!WARNING!!\n"
> +        printf "!!WARNING!!      If you proceed this will destroy all data on your local system, and      !!WARNING!!\n"
> +        printf "!!WARNING!!             your hard disk will be irreversably reconfiguration.              !!WARNING!!\n"
> +        printf "!!WARNING!!                                                                               !!WARNING!!\n"
> +        printf "!!WARNING!!                                                                               !!WARNING!!\n"
> +        printf "!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!\n"
> +        printf "!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!\n"
> +        printf "\n"
> +        printf "\tContinue? (Y/n) "
> +        read
> +        case $REPLY in
> +            Y|y)
> +                perform_partitioning; break ;;
> +            N|n)  return ;;
> +        esac
> +    done
> +}

How about this replacement I proposed a few days ago?

  All the warning code below is hard to read in source form,
  and the output wraps on my 80-column console, so how about
  something like this instead?

  sp='                                                    '
  w='!!WARNING'
  wb="$w"'!!'
  w8="$w$w$w$w$w$w$w$w"
  printf '%s!!\n' \
    "$w8" \
    "$w8" \
    "$wb$sp$w" \
    "$wb$sp$w" \
    "$wb      If you proceed, this will destroy all data on your local"     \
    "$wb      system, and your hard disk will be irreversably reconfigured" \
    "$wb$sp$w" \
    "$wb$sp$w" \
    "$w8" \
    "$w8"


> +DRIVE=$(for drive in `hal-find-by-capability --capability storage`; do
> +    info=$(lshal -u $drive -s)
> +    if [[ $info =~ "storage.drive_type = 'disk'" ]]; then
> +         lshal -u $drive -s | awk ' /block.device/ {
> +                match($0, "block.device = *'"'"'(.*)'"'"'", device)
> +                printf "%s", device[1]
> +        }'
> +    fi
> +done)
> +
> +SPACE=$(for drive in `hal-find-by-capability --capability storage`; do
> +    info=$(lshal -u $drive -s)
> +    if [[ $info =~ "storage.drive_type = 'disk'" ]]; then
> +         lshal -u $drive -s | awk ' /storage.size/ {
> +                match($0, "storage.size *= *([0-9]+)", device)
> +                printf "%s", device[1]
> +        }'
> +    fi
> +done)
> +
> +SPACE=$(echo "scale=0; $SPACE / (1024 * 1024)" | bc -l)
> +BOOT_SIZE="256"
> +ROOT_SIZE="256"
> +CONFIG_SIZE="5"
> +LOGGING_SIZE="256"
> +
> +MEM_SIZE=$(virsh -c qemu:///system nodeinfo | awk '/Memory size/ { print $3 }')
> +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l)
> +SWAP_SIZE=$MEM_SIZE

It's probably worthwhile to sanity-check this:

  case $MEM_SIZE in
    ''|*[^0-9]*) die failed to get system memory size;;
  esac

And while testing the above, I noticed that you must be root,
which this script is, of course.  But there's no need for auth
in this case, so might as well use --readonly:

    MEM_SIZE=$(virsh --readonly -c qemu:///system nodeinfo \
               | awk '/Memory size/ { print $3 }')

> +# If the any partition size was provided as a kernel argument,
> +# then set the values and run without prompting
> +
> +counter=0
> +while [ "$1" != "" ]; do
> +    AUTO="Y"
> +    case $counter in
> +        0) SWAP_SIZE=$1;    break ;;
> +        1) BOOT_SIZE=$1;    break ;;
> +        2) ROOT_SIZE=$1;    break ;;
> +        3) LOGGING_SIZE=$1; break ;;
> +    esac
> +    counter=`expr $counter + 1 `

stray space.

> +    shift
> +done
> +
> +if [ "$AUTO" == "Y" ]; then
> +    printf "Partitioning hard disk..."
> +    perform_partitioning
> +    printf "[DONE]\n"
> +    exit 0
> +else
> +    while true; do
> +        do_resolve_sizes
> +
> +        OPTIONS="Configure Review Partition Quit"
> +        PS3="Choose an option: "
> +
> +        printf "\n"
> +
> +        select OPTION in $OPTIONS
> +        do
> +            case "$OPTION" in
> +                "Configure") do_configure ; break ;;
> +                "Review")    do_review    ; break ;;
> +                "Partition") do_confirm   ; break ;;
> +                "Quit")      exit ;;
> +            esac
> +        done
> +    done
> +fi

I've added this function, current not used anywhere:

check_partition_sizes()
{
    # FIXME: use this function before performing any partitioning, auto or not
    :
    # Perform some sanity checks.  E.g.,
    # What if DATA_SIZE ends up zero or negative?
    # What if any of those partition sizes is smaller than
    # the minimum size for an ext3 partition?  Diagnose it here
    # or just let the mke2fs failure suffice.
}

Also, I switched the function-definition syntax, "function NAME { ... }"
to the POSIX syntax: "NAME() { ... }".
Using "function" as a keyword is a bashism.

Also, I moved the "do_resolve_sizes" call out of the while loop,
to be called once just before it, instead.
It's not needed in the loop, since the only thing that changes
its inputs in the loop (do_configure) also calls do_resolve_sizes.

In testing this simply by running the script as non-root
on my desktop, I get a mess, due to the fact that there is
more than one matching "storage" device:

    $ /t/ovirt-config-storage

    1) Configure
    2) Review
    3) Partition
    4) Quit
    Choose an option: 2

    The local disk will be repartitioned as follows:
    ================================================
               Physical Hard Disk: /dev/dm-1/dev/dm-0/dev/ram9/dev/ram8/dev/ram7/dev/ram6/dev/ram5/dev/ram4/dev/ram3/dev/ram2/dev/ram15/dev/ram14/dev/ram13/dev/ram12/dev/ram11/dev/ram10/dev/ram1/dev/ram0/dev/loop7/dev/loop6/dev/loop5/dev/loop4/dev/loop3/dev/loop2/dev/loop1/dev/loop0/dev/sdb/dev/sda
          Total storage available: 81920000009523200000016000000160000001600000016000000160000001600000\
    01600000016000000160000001600000016000000160000001600000016000000160\
    000001600000000000000476940023437976940 MB
              Swap partition size: 8005 MB
              Boot partition size: 256 MB
      Installation partition size: 256 MB
     Configuration partition size: 5 MB
           Logging partition size: 256 MB
              Data partition size: 81920000009523200000016000000160000001600000016000000160000001600000\
    01600000016000000160000001600000016000000160000001600000016000000160\
    000001600000000000000476940023437968679
    -517 MB

    1) Configure
    2) Review
    3) Partition
    4) Quit
    Choose an option:

This just shows that the node is assumed to have only one disk device.
Do we _need_ to account for any other scenario?
For now I'm not even trying to deal with alternatives.

------------------
Here's an amended patch with all of the above changes:

>From 6ceaf55b8cd9a719340d83c8fb87d2f1c98c4743 Mon Sep 17 00:00:00 2001
From: Darryl L. Pierce <dpierce at redhat.com>
Date: Thu, 13 Nov 2008 17:05:28 -0500
Subject: [PATCH node] Added support for local storage configuration.

This patch wipes out the entire disk on the node and replaces it with
a set of partitions. The partitions are a raw partition to hold the bootable
kernel, and the rest of the disk is taken up as an physical volume.

On the physical volume is created the following logical volumes:

 * SWAP    - swap partition
 * ROOT    - to host the node image
 * CONFIG  - to hold node configuration data
 * LOGGING - to hold local logs
 * DATA    - to hold VM images

Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
 scripts/ovirt-config-storage |  213 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 213 insertions(+), 0 deletions(-)

diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage
index c856ef1..797aee4 100755
--- a/scripts/ovirt-config-storage
+++ b/scripts/ovirt-config-storage
@@ -1,2 +1,215 @@
 #!/bin/bash
 #
+# To automate the partitioning, pass in the specific fields in this order
+# ovirt-config-storage [swap size] [boot size] [root size] [logging size]
+#
+# All sizes are in megabytes
+#
+
+ME=$(basename "$0")
+warn() { printf '%s: %s\n' "$ME" "$*" >&2; }
+die() { warn "$*"; exit 1; }
+
+do_resolve_sizes()
+{
+    DATA_SIZE=$(printf '%s\n' 'scale=0' \
+                "$SPACE - $BOOT_SIZE - $SWAP_SIZE
+                 - $ROOT_SIZE - $CONFIG_SIZE - $LOGGING_SIZE" | bc -l)
+}
+
+check_partition_sizes()
+{
+    # FIXME: use this function before performing any partitioning, auto or not
+    :
+    # Perform some sanity checks.  E.g.,
+    # What if DATA_SIZE ends up zero or negative?
+    # What if any of those partition sizes is smaller than
+    # the minimum size for an ext3 partition?  Diagnose it here
+    # or just let the mke2fs failure suffice.
+}
+
+do_configure()
+{
+    for i in swap boot root logging; do
+        uc=$(echo $i|tr '[[:lower:]]' '[[:upper:]]')
+        var=${uc}_SIZE
+        eval "size=\$$var"
+        read -p "$i partition size (Currently $size MB)? "
+        if [[ $REPLY =~ ^[0-9]+$ ]] && [[ $REPLY -gt 0 ]]; then
+            eval "$var=$REPLY"
+        else
+            printf "invalid value: '$i'.  retaining $size MB.\n"
+        fi
+    done
+
+    do_resolve_sizes
+}
+
+do_review()
+{
+    cat <<EOF
+
+The local disk will be repartitioned as follows:
+================================================
+           Physical Hard Disk: $DRIVE
+      Total storage available: $SPACE MB
+          Swap partition size: $SWAP_SIZE MB
+          Boot partition size: $BOOT_SIZE MB
+  Installation partition size: $ROOT_SIZE MB
+ Configuration partition size: $CONFIG_SIZE MB
+       Logging partition size: $LOGGING_SIZE MB
+          Data partition size: $DATA_SIZE MB
+
+EOF
+}
+
+perform_partitioning()
+{
+    printf "Preparing local storage. Please wait..."
+
+    {
+    # Exit upon any failure.
+    set -e
+
+    vgroups=$(vgdisplay -C | awk '{ print $1" "; }')
+    vgremove -f $vgroups
+
+    dd if=/dev/zero of=$DRIVE bs=1K count=1
+    blockdev --rereadpt $DRIVE
+    partprobe -s $DRIVE
+
+    parted $DRIVE -s "mklabel gpt"
+    parted $DRIVE -s "mkpart primary ext2 0M ${BOOT_SIZE}M"
+    parted $DRIVE -s "mkpart primary ext2 ${BOOT_SIZE}M ${SPACE}M"
+    parted $DRIVE -s "set 2 lvm on"
+
+    pvcreate "${DRIVE}2"
+    pvck
+    vgcreate /dev/HostVG "${DRIVE}2"
+
+    lvcreate --name Swap    --size ${SWAP_SIZE}M    /dev/HostVG
+    lvcreate --name Root    --size ${ROOT_SIZE}M    /dev/HostVG
+    lvcreate --name Config  --size ${CONFIG_SIZE}M  /dev/HostVG
+    lvcreate --name Logging --size ${LOGGING_SIZE}M /dev/HostVG
+    lvcreate --name Data    -l 100%FREE             /dev/HostVG
+
+    mke2fs -T ext3 "${DRIVE}1"         -L "BOOT"
+    tune2fs -c 0 -i 0 "${DRIVE}1"
+    mkswap /dev/HostVG/Swap
+    mke2fs -T ext3 /dev/HostVG/Root    -L "ROOT"
+    tune2fs -c 0 -i 0 /dev/HostVG/Root
+    mke2fs -T ext3 /dev/HostVG/Config  -L "CONFIG"
+    tune2fs -c 0 -i 0 /dev/HostVG/Config
+    mke2fs -T ext3 /dev/HostVG/Logging -L "LOGGING"
+    tune2fs -c 0 -i 0 /dev/HostVG/Logging
+    mke2fs -T ext3 /dev/HostVG/Data    -L "DATA"
+    tune2fs -c 0 -i 0 /dev/HostVG/Data
+    } > /var/log/ovirt-partition.log 2>&1
+
+    printf "Completed!\n\n"
+}
+
+do_confirm()
+{
+    while true; do
+        sp='                                                    '
+        w='!!WARNING'
+        wb="$w"'!!'
+        w8="$w$w$w$w$w$w$w$w"
+        printf '%s!!\n' \
+          "$w8" \
+          "$w8" \
+          "$wb$sp$w" \
+          "$wb$sp$w" \
+          "$wb    If you proceed, this will destroy all data on your local" \
+          "$wb    system, and your hard disk will be irreversably reconfigured" \
+          "$wb$sp$w" \
+          "$wb$sp$w" \
+        "$w8" \
+        "$w8"
+        printf "\n\tContinue? (Y/n) "
+        read
+        case $REPLY in
+            Y|y)
+                perform_partitioning; break ;;
+            N|n)  return ;;
+        esac
+    done
+}
+
+DRIVE=$(for drive in `hal-find-by-capability --capability storage`; do
+    info=$(lshal -u $drive -s)
+    if [[ $info =~ "storage.drive_type = 'disk'" ]]; then
+         lshal -u $drive -s | awk ' /block.device/ {
+                match($0, "block.device = *'"'"'(.*)'"'"'", device)
+                printf "%s", device[1]
+        }'
+    fi
+done)
+
+SPACE=$(for drive in `hal-find-by-capability --capability storage`; do
+    info=$(lshal -u $drive -s)
+    if [[ $info =~ "storage.drive_type = 'disk'" ]]; then
+         lshal -u $drive -s | awk ' /storage.size/ {
+                match($0, "storage.size *= *([0-9]+)", device)
+                printf "%s", device[1]
+        }'
+    fi
+done)
+
+SPACE=$(echo "scale=0; $SPACE / (1024 * 1024)" | bc -l)
+BOOT_SIZE="256"
+ROOT_SIZE="256"
+CONFIG_SIZE="5"
+LOGGING_SIZE="256"
+
+MEM_SIZE=$(virsh --readonly -c qemu:///system nodeinfo \
+           | awk '/Memory size/ { print $3 }')
+case $MEM_SIZE in
+    ''|*[^0-9]*) die failed to get system memory size;;
+esac
+
+MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l)
+SWAP_SIZE=$MEM_SIZE
+
+# If the any partition size was provided as a kernel argument,
+# then set the values and run without prompting
+
+counter=0
+while [ "$1" != "" ]; do
+    AUTO="Y"
+    case $counter in
+        0) SWAP_SIZE=$1;    break ;;
+        1) BOOT_SIZE=$1;    break ;;
+        2) ROOT_SIZE=$1;    break ;;
+        3) LOGGING_SIZE=$1; break ;;
+    esac
+    counter=`expr $counter + 1`
+    shift
+done
+
+if [ "$AUTO" == "Y" ]; then
+    printf "Partitioning hard disk..."
+    perform_partitioning
+    printf "[DONE]\n"
+    exit 0
+else
+    do_resolve_sizes
+    while true; do
+
+        OPTIONS="Configure Review Partition Quit"
+        PS3="Choose an option: "
+
+        printf "\n"
+
+        select OPTION in $OPTIONS
+        do
+            case "$OPTION" in
+                "Configure") do_configure ; break ;;
+                "Review")    do_review    ; break ;;
+                "Partition") do_confirm   ; break ;;
+                "Quit")      exit ;;
+            esac
+        done
+    done
+fi
--
1.6.0.4.911.gc990




More information about the ovirt-devel mailing list