[Ovirt-devel] [PATCH] oVirt Node local installation

Alan Pevec apevec at redhat.com
Thu Aug 7 07:35:41 UTC 2008


oVirt partition can be initialized on a local flash or disk drive.
oVirt partition is a local primary ext2 partition, labeled OVIRT,
which contains:
 /config - local oVirt configuration (ktab, local admin password...)
 /boot - boot loader, kernel and initramfs
 /LiveOS - oVirt Node compressed livecd image

oVirt partition is initialized using kernel boot parameters:
  ovirt_init=usb|scsi[:serial#]
local installation target disk
usb|scsi - select disk type, as reported by udev ID_BUS
serial# - select exact disk using serial number, as reported by
          udev ID_SERIAL [1]
e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0

  ovirt_local_boot
install/update oVirt Node image on the local installation target disk
without this parameter oVirt partition is used for storing
oVirt configuration only

[1] one-liner to list serial#s for all disks in the system:
for d in /dev/sd?; do eval $(udevinfo --query env --name $d); echo $d $ID_SERIAL;done

Signed-off-by: Alan Pevec <apevec at redhat.com>
---
 ovirt-host-creator/common-pkgs.ks              |    1 -
 ovirt-managed-node/src/scripts/ovirt           |   64 +++++--
 ovirt-managed-node/src/scripts/ovirt-awake     |   10 +-
 ovirt-managed-node/src/scripts/ovirt-early     |  248 +++++++++++++++++++++++-
 ovirt-managed-node/src/scripts/ovirt-functions |    3 +
 ovirt-managed-node/src/scripts/ovirt-post      |    2 +-
 6 files changed, 298 insertions(+), 30 deletions(-)

diff --git a/ovirt-host-creator/common-pkgs.ks b/ovirt-host-creator/common-pkgs.ks
index 2d1ad6e..bc08358 100644
--- a/ovirt-host-creator/common-pkgs.ks
+++ b/ovirt-host-creator/common-pkgs.ks
@@ -48,7 +48,6 @@ ovirt-managed-node
 -rhpl
 -kbd
 -usermode
--grub
 -fedora-logos
 -kpartx
 -dmraid
diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt
index 92ed330..b6dcbc6 100755
--- a/ovirt-managed-node/src/scripts/ovirt
+++ b/ovirt-managed-node/src/scripts/ovirt
@@ -15,36 +15,70 @@ start() {
     # and it needs to be at the front of the forward chain
     iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT
 
+    krb5_conf=/etc/krb5.conf
+    krb5_tab=/etc/libvirt/krb5.tab
+    # retrieve config from local oVirt partition if available
+    #   krb5.conf krb5.tab
+    #   TODO local admin password, ssh server key - what else?
+    ovirt=$(mktemp -d)
+    cfg=$ovirt/config
+    mount -r /dev/disk/by-label/$OVIRT_LABEL $ovirt
+    if [ -e $cfg/krb5.conf ]; then
+      cp -a $cfg/krb5.conf $krb5_conf
+    fi
+    if [ -e $cfg/krb5.tab ]; then
+      cp -a $cfg/krb5.tab $krb5_tab
+    fi
+    if [ -s $krb5_tab ]; then
+      krb5_tab=
+    fi
+
     find_srv ipa tcp
-    if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then
-        krb5_conf=/etc/krb5.conf
-        if [ ! -s $krb5_conf ]; then
-            rm -f $krb5_conf
-            # FIXME this is IPA specific
-            wget -q \
-                http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \
-                || (echo "Failed to get $krb5_conf" && return 1)
+    if [ -n "$SRV_HOST" -a -n "$SRV_PORT" -a ! -s $krb5_conf ]; then
+        rm -f $krb5_conf
+        # FIXME this is IPA specific
+        wget -q \
+            http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf
+        if [ $? -ne 0 ]; then
+            echo "Failed to get $krb5_conf"; return 1
+        fi
+        # store config in oVirt partition
+        if [ -e $cfg ]; then
+            mount -o remount,rw $ovirt
+            cp -a $krb5_conf $cfg/krb5.conf
         fi
     else
-        echo "skipping Kerberos configuration, IPA service not available"
+        echo "skipping Kerberos configuration"
     fi
 
     find_srv identify tcp
     if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then
-        krb5_tab=/etc/libvirt/krb5.tab
-        ovirt-awake start $krb5_tab $SRV_HOST $SRV_PORT
+        ovirt-awake start $SRV_HOST $SRV_PORT $krb5_tab
+        if [ $? -ne 0 ]; then
+            echo "ovirt-awake failed"; return 1
+        fi
+        # store config in oVirt partition
+        if [ -n "$krb_tab" -a -e $cfg ]; then
+            mount -o remount,rw $ovirt
+            cp -a $krb5_tab $cfg/krb5.tab
+        fi
     else
-        echo "skipping ovirt-awake, oVirt registration service not available"
+        echo "skipping ovirt-awake, oVirt identify service not available"
     fi
 
+    # cleanup
+    umount $ovirt && rmdir $ovirt
+
     find_srv collectd tcp
     if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then
         if [ -f $collectd_conf.in ]; then
             collectd_conf=/etc/collectd.conf
             sed -e "s/@COLLECTD_SERVER@/$SRV_HOST/" \
                 -e "s/@COLLECTD_PORT@/$SRV_PORT/" $collectd_conf.in \
-                > $collectd_conf \
-                || (echo "Failed to write $collectd_conf" && return 1)
+                > $collectd_conf
+            if [ $? -ne 0 ]; then
+                echo "Failed to write $collectd_conf"; return 1
+            fi
         fi
     else
         echo "skipping collectd configuration, collectd service not available"
@@ -53,7 +87,7 @@ start() {
 
 case "$1" in
     start)
-        echo -n $"Starting ovirt: "
+        printf "Starting ovirt: "
 
         {
             start
diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake
index 38d405e..fc03c9a 100755
--- a/ovirt-managed-node/src/scripts/ovirt-awake
+++ b/ovirt-managed-node/src/scripts/ovirt-awake
@@ -63,10 +63,10 @@ start () {
 
             KEYTAB=`echo $REPLY | awk '{ print $2 }'`
 
-            if [ -n $KEYTAB ]; then
+            if [ -n "$KEYTAB" -a -n "$KEYTAB_FILE" ]; then
                 echo "Retrieving keytab: '$KEYTAB'"
 
-                wget -q $KEYTAB --output-document=$KEYTAB_FILE
+                wget -q "$KEYTAB" --output-document="$KEYTAB_FILE"
             else
                 echo "No keytab to retrieve"
             fi
@@ -84,9 +84,9 @@ start () {
 
 case "$1" in
     start)
-        KEYTAB_FILE=$2
-        SRV_HOST=$3
-        SRV_PORT=$4
+        SRV_HOST=$2
+        SRV_PORT=$3
+        KEYTAB_FILE=$4
         start
         RETVAL=$?
     ;;
diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early
index aa0a49c..dada566 100755
--- a/ovirt-managed-node/src/scripts/ovirt-early
+++ b/ovirt-managed-node/src/scripts/ovirt-early
@@ -10,6 +10,9 @@
 . /etc/init.d/functions
 . /etc/init.d/ovirt-functions
 
+# size of the oVirt partition in megabytes
+OVIRT_SIZE=64
+
 configure_from_network() {
     DEVICE=$1
     if [ -n "$DEVICE" ]; then
@@ -51,21 +54,250 @@ configure_from_network() {
     printf "default config applied."
 }
 
+# find_disk $bus $serial
+find_disk() {
+    local bus=$1
+    local serial=$2
+    local live=$(readlink -e /dev/live)
+    live=${live%[1-4]}
+    for d in /dev/sd?; do
+      eval $(udevinfo --query env --name $d)
+      if [ "$ID_BUS" = "$bus" ]; then
+        if [ -z "$serial" -o "$ID_SERIAL" = "$serial" ]; then
+          # cannot install LiveOS over itself
+          if [ -n "$live" -a "$d" = "$live" ]; then
+            return 2
+          else
+            echo $d
+            return 0
+          fi
+        fi
+      fi
+    done
+    return 1
+}
+
+# local_install $local_os $target
+#  local_os - 1=install LiveOS and boot loader
+#             0=initialize oVirt partition only
+#  target - target disk to hold the oVirt partition
+#           usb|scsi[:serial#]
+#
+# oVirt partition is a local primary ext2 partition, labeled OVIRT,
+# which contains:
+#  /config - local oVirt configuration (ktab, local admin password)
+#  /boot - boot loader, kernel and initramfs
+#  /LiveOS - oVirt Node compressed livecd image
+
+local_install() {
+    local local_os=$1
+    local target=$2
+    local disk
+    local part
+    local live_dev=/dev/live
+    if [ ! -e $live_dev ]; then
+      # PXE boot
+      live_dev=/dev/loop0
+    fi
+    local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL)
+    local ovirt_disk=${ovirt_part%[1-4]}
+    if [ "$ovirt_disk" = "$ovirt_part" ]; then
+      ovirt_disk=
+    fi
+    if [ -z "$target" ]; then
+        live_part=$(readlink -e $live_dev)
+        if [ -z "$ovirt_disk" -o "$ovirt_part" = "$live_part" ]; then
+          return 1
+        fi
+        mode=update
+        disk=$ovirt_disk
+        part=$ovirt_part
+    else
+      case "$target" in
+          scsi*)
+          bus=scsi
+          serial=${target#scsi:}
+          ;;
+          usb*)
+          bus=usb
+          serial=${target#usb:}
+          ;;
+          *)
+          return 1
+          ;;
+      esac
+      if [ "$serial" = "$bus" ]; then
+        serial=
+      fi
+      disk=$(find_disk $bus $serial)
+      rc=$?
+      if [ $rc -eq 2 ]; then
+        echo "target '$target' is the boot disk, aborting install"
+        return 1
+      elif [ $rc -ne 0 ]; then
+        echo "target disk '$target' not found"
+        return 1
+      fi
+      mode=install
+      if [ -n "$ovirt_disk" ]; then
+        if [ "$disk" = "$ovirt_disk" ]; then
+          # target disk contains oVirt partition, select it for update
+          # TODO force install option
+          mode=update
+          part=$ovirt_part
+        else
+          # remove label from oVirt partition, there can be only one
+          e2label $ovirt_part ""
+        fi
+      fi
+      if [ "$mode" = "install" ]; then
+        printf "installing $disk..." | tee /dev/console
+        dd if=/dev/zero bs=4096 count=1 of=$disk \
+        && parted -s $disk mklabel msdos \
+        && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \
+        && partprobe -s $disk
+        if [ $? -ne 0 ]; then
+          echo "$disk partition creation failed"; return 1
+        fi
+        part=${disk}1
+        udevsettle
+        mkfs.ext2 -L $OVIRT_LABEL $part \
+        && tune2fs -c0 -i0 $part
+        if [ $? -ne 0 ]; then
+          echo "$disk ext2 creation failed"; return 1
+        fi
+        # update by-label link manually, mkfs won't trigger udev
+ls -l /dev/disk
+        mkdir -p /dev/disk/by-label
+ls -l /dev/disk/by-label
+        ln -sf $part /dev/disk/by-label/$OVIRT_LABEL
+      fi
+    fi
+
+    if [ "$mode" = "update" ]; then
+      printf "updating $ovirt_disk..." | tee /dev/console
+    fi
+    ovirt=$(mktemp -d)
+    live=$(mktemp -d)
+    mount -r $live_dev $live
+    if [ $? -ne 0 ]; then
+      echo "source image mount failed"; return 1
+    fi
+    mount $part $ovirt
+    if [ $? -ne 0 ]; then
+      echo "target mount failed"; return 1
+    fi
+    mkdir -p $ovirt/config
+    # update local config using embedded in livecd image
+    # TODO admin tool for adding /config into livecd image
+    if [ -e $live/config/krb5.conf ]; then
+      cp -a $live/config/krb5.conf $ovirt/config \
+      || echo "krb5.conf copy failed"
+    fi
+    if [ -e $live/config/krb5.tab ]; then
+      cp -a $live/config/krb5.tab $ovirt/config \
+      || echo "krb5.tab copy failed"
+    fi
+
+    if [ $local_os = 0 ]; then
+      # config update only, cleanup and continue booting
+      umount $ovirt && rmdir $ovirt
+      umount $live && rmdir $live
+    else
+      # install oVirt Node image for local boot
+      if [ -e "$live/syslinux" ]; then
+        syslinux=syslinux
+      elif [ -e "$live/isolinux" ]; then
+        syslinux=isolinux
+      else
+        syslinux=
+      fi
+      rm -rf $ovirt/boot
+      rm -rf $ovirt/LiveOS
+      mkdir -p $ovirt/boot/grub
+      mkdir -p $ovirt/LiveOS
+      cp -a $live/LiveOS/squashfs.img $ovirt/LiveOS \
+      && cp -a $live/$syslinux/initrd0.img $ovirt/boot \
+      && cp -a $live/$syslinux/vmlinuz0 $ovirt/boot
+      if [ $? -ne 0 ]; then
+        echo "image copy failed"; return 1
+      fi
+      part_num=$(( ${part#$disk} - 1 ))
+      cat > $ovirt/boot/grub/grub.conf <<EOF
+default=0
+timeout=2
+hiddenmenu
+title oVirt Managed Node
+    root (hd0,$part_num)
+    kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg
+    initrd /boot/initrd0.img
+EOF
+      grub-install --root-directory=$ovirt $disk >&2
+      if [ $? -ne 0 ]; then
+        echo "boot loader install failed"; return 1
+      fi
+      # remove 1.5 stages we don't need
+      find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \
+        -exec rm {} \;
+      # FIXME avoid reboot loops
+      # - cobbler: pxe-only-once, needs xmlrpc to cobbler server
+      # - plain dnsmasq with tftp: ?
+      # temp. workaround:
+      printf "oVirt local installation finished, press Enter to reboot." \
+        > /dev/console
+      read key
+      if [ "$key" = "debug" ]; then
+        sh > /dev/console 2>&1
+      fi
+      reboot
+    fi
+}
+
 start() {
-    # find boot interface from cmdline
-    # IPAPPEND 2 in pxelinux.cfg appends e.g. BOOTIF=01-00-16-3e-12-34-57
-    BOOTIF=
+    # oVirt boot parameters
+    #   BOOTIF=<MAC> (appended by pxelinux)
+    #   ovirt_init=usb|scsi[:serial#]
+    #   ovirt_local_boot
+
+    #   BOOTIF=<MAC> (appended by pxelinux)
+    # network boot interface is assumed to be on management network where
+    # oVirt Server is reachable
+    # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node
+    # e.g. BOOTIF=01-00-16-3e-12-34-57
+    bootif=
+
+    #   ovirt_init=usb|scsi[:serial#]
+    # local installation target disk
+    # usb|scsi - select disk type, as reported by udev ID_BUS
+    # serial# - select exact disk using serial number, as reported by
+    #           udev ID_SERIAL
+    # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0
+    target=
+
+    #   ovirt_local_boot
+    # install/update oVirt Node image on the local installation target disk
+    local_os=0
+
     for i in $(cat /proc/cmdline); do
         case $i in
             BOOTIF=??-??-??-??-??-??-??)
-            i=${i/#BOOTIF=??-/}
-            BOOTMAC=${i//-/:}
-            BOOTIF=$(grep -l $BOOTMAC /sys/class/net/eth*/address|rev|cut -d/ -f2|rev)
+            i=${i#BOOTIF=??-}
+            bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev)
+            ;;
+            ovirt_init=*)
+            target=${i#ovirt_init=}
+            ;;
+            ovirt_local_boot)
+            local_os=1
             ;;
         esac
     done
 
-    configure_from_network $BOOTIF
+    # TODO pass extra kernel params from /proc/cmdline e.g. console=...
+    set -x
+    local_install $local_os $target
+    set +x
+    configure_from_network $bootif
 
     # find all of the partitions on the system
 
@@ -96,7 +328,7 @@ start() {
 
 case "$1" in
     start)
-        echo -n $"Starting ovirt-early: "
+        printf "Starting ovirt-early: "
 
         {
             start
diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions
index 5b530f7..083e13d 100644
--- a/ovirt-managed-node/src/scripts/ovirt-functions
+++ b/ovirt-managed-node/src/scripts/ovirt-functions
@@ -2,6 +2,9 @@
 
 OVIRT_LOGFILE=/var/log/ovirt.log
 
+# label of the oVirt partition
+OVIRT_LABEL=OVIRT
+
 find_srv()
 {
     local dnsreply
diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post
index ecc6ff4..1267f40 100755
--- a/ovirt-managed-node/src/scripts/ovirt-post
+++ b/ovirt-managed-node/src/scripts/ovirt-post
@@ -22,7 +22,7 @@ start() {
 
 case "$1" in
     start)
-        echo -n $"Starting ovirt-post: "
+        printf "Starting ovirt-post: "
 
         {
             start
-- 
1.5.5.1




More information about the ovirt-devel mailing list