yay customized preseeds + functional pkvlm-create
authorTero Marttila <terom@fixme.fi>
Tue, 13 Dec 2011 20:17:57 +0200
changeset 1 51b1db97f448
parent 0 0b1089c8a8ac
child 2 221db3973c99
yay customized preseeds + functional pkvlm-create
pkvlm-create
preseed/isolinux.cfg
preseed/preseed.cfg
scripts/lib.sh
--- a/pkvlm-create	Sat Dec 10 17:06:27 2011 +0200
+++ b/pkvlm-create	Tue Dec 13 20:17:57 2011 +0200
@@ -1,46 +1,143 @@
 #!/bin/bash
-BRIDGE=br-lan
-RAM=1024
-VCPUS=2
-IMAGE=isos/debian-6.0.3-amd64-netinst_preseed.iso
-IMAGE_VARIANT=debiansqueeze
 
+### Parameters
+## Options
+_MOCK=${_MOCK:0}
 
-NAME=$1
-VG=pvl
-DISK_NAME=${NAME}
-DISK=/dev/mapper/${VG}-$DISK_NAME
+## Guest info
+GUEST_NAME=asdf2
+
+# Basic params
+GUEST_RAM=1G
+GUEST_VCPUS=2
+
+# OS variant (for virt-install)
+GUEST_OS_VARIANT=debiansqueeze
+
+## Disk
+# Size of LV to create
 DISK_SIZE=10G
 
-PRESEED_FILE=/cdrom/preseed.cfg
-PRESEED_CHECKSUM=35ea42c7b0139aab26284a96c0ec8c31
-
-PRESEED_BOOT={preseed/file=$PRESEED_FILE preseed/file/checksum=$PRESEED_CHECKSUM}
+# LVM vg to use
+DISK_VG=pvl
 
-# env
-LVCREATE=/sbin/lvcreate
-VIRT_INSTALL=/usr/bin/virt-install
+# LVM lv to use
+DISK_NAME=${GUEST_NAME}
 
-LIBVIRT_URL=qemu:///system
-VIRT_TYPE=kvm
+# Path to disk block device
+DISK_PATH=/dev/mapper/${DISK_VG}-${DISK_NAME}
+DISK_BUS=virtio
+GUEST_DISK=/dev/vda
 
+## Network
+NET_BRIDGE=br-lan
+NET_IPADDR=194.197.235.36
+
+## Installation image
+# Original Debian Installer image (iso)
+INSTALLER_NAME="debian-6.0.3-amd64"
+INSTALLER_ISO="iso-in/${INSTALLER_NAME}-netinst.iso"
+INSTALLER_TREE="iso-in/$INSTALLER_NAME"
+INSTALLER_FLAG="${INSTALLER_TREE}.unpacked"
+
+# Customized preseed image name
+INSTALL_NAME="debian-6.0.3-amd64_${GUEST_NAME}"
+
+# Customized image content
+INSTALL_TREE="images/${INSTALL_NAME}"
+INSTALL_ISO="iso-out/${INSTALL_NAME}.iso"
+
+# Preseed output file in install tree
+INSTALL_PRESEED_NAME="preseed.cfg"
+INSTALL_PRESEED_FILE="${INSTALL_TREE}/${INSTALL_PRESEED_NAME}"
+INSTALL_PRESEED_CHECKSUM= # set later
+
+# Preseed source template
+PRESEED_TEMPLATE="preseed/preseed.cfg"
+PRESEED_ISOLINUX="preseed/isolinux.cfg"
+PRESEED_REST="preseed/passwords.cfg"
+
+## External progs
+# Bootable .iso for Debian isolinux-based installer CDs
+GENISOIMAGE=/usr/bin/genisoimage
+GENISOIMAGE_OPTS="-r -J -no-emul-boot -boot-load-size 4 -boot-info-table -b isolinux/isolinux.bin -c isolinux/boot.cat"
+
+# LVM
+LVM=/sbin/lvm
+
+# Libvirt --connect URL
+LIBVIRT=qemu:///system
+VIRSH=/usr/bin/virsh
+
+function virsh () {
+    $VIRSH --connect $LIBVIRT "$@"
+}
+
+# type of guest to create
+LIBVIRT_TYPE=kvm
+
+# virt-install
+VIRT_INSTALL="/usr/bin/virt-install"
+
+## SELinux?
 #SEMANAGE=/usr/sbin/semanage
 #RESTORECON=/sbin/restorecon
 
-# functions
+### Functions
+set -u
 set -e
 
-function cmd () {
-    echo ">>> $@"
-    eval "$@" || exit $?
-}
+scripts=$(dirname $0)/scripts
+. $scripts/lib.sh
 
+### Check
+# VM exists?
+if cmd virsh domid ${GUEST_NAME} 2> /dev/null; then
+    die "Virtual machine already exists: ${GUEST_NAME}"
+fi
+
+# Installer exists?
+if cmd test ! -f ${INSTALLER_ISO}; then
+    die "Installer not found: ${INSTALLER_ISO}"
+fi
 
 ### Go!
+# Extract .iso
+if [ -f ${INSTALLER_FLAG} ]; then
+    echo "Installer already unpacked: ${INSTALLER_TREE}"
+
+else
+    echo "Unpacking installer: ${INSTALLER_ISO}"
+    cmd extract_iso ${INSTALLER_ISO} ${INSTALLER_TREE}
+    cmd touch ${INSTALLER_FLAG}
+fi
+
+# Copy to customized tree
+cmd cp -r ${INSTALLER_TREE} ${INSTALL_TREE}
+cmd chmod -R u=rwX,og=rX ${INSTALL_TREE}
+
+# XXX: Customize preseed
+cmd expand_template ${PRESEED_TEMPLATE} ${INSTALL_PRESEED_FILE}
+
+# md5sum
+INSTALL_PRESEED_CHECKSUM=$(my_md5sum $INSTALL_PRESEED_FILE)
+
+# Isolinux .cfg
+cmd expand_template ${PRESEED_ISOLINUX} ${INSTALL_TREE}/isolinux/isolinux.cfg
+
+# Others
+for file in ${PRESEED_REST}; do
+    name=$(basename $file)
+
+    cmd expand_template $file ${INSTALL_TREE}/${name}
+done
+
+# Create .iso
+cmd ${GENISOIMAGE} -o ${INSTALL_ISO} ${GENISOIMAGE_OPTS} ${INSTALL_TREE}
 
 ## LVM
-[ -e $DISK ] || cmd $LVCREATE -L $DISK_SIZE -n $DISK_NAME $VG
-
+# Create LV (unless it already exists)
+[ -e $DISK_PATH ] || cmd sudo $LVM lvcreate -L $DISK_SIZE -n $DISK_NAME $DISK_VG
 
 ## SELinux?
 #$SEMANAGE fcontext -a -t virt_image_t $DISK
@@ -48,15 +145,15 @@
 
 ## virt-install
 cmd $VIRT_INSTALL \
-        --connect $LIBVIRT_URL \
-        --name $NAME \
-        --ram $RAM --vcpus $VCPUS \
-        --cdrom "$IMAGE" \
-        --os-variant $IMAGE_VARIANT \
-        --disk path=$DISK,bus=virtio \
-        --network bridge:$BRIDGE \
+        --connect $LIBVIRT \
+        --name $GUEST_NAME \
+        --ram $(expand_MB $GUEST_RAM) --vcpus $GUEST_VCPUS \
+        --cdrom "$INSTALL_ISO" \
+        --os-variant $GUEST_OS_VARIANT \
+        --disk path=$DISK_PATH,bus=$DISK_BUS \
+        --network bridge:$NET_BRIDGE \
         --vnc \
-        --virt-type $VIRT_TYPE \
+        --virt-type $LIBVIRT_TYPE \
         --accelerate --hvm \
         --serial pty
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/preseed/isolinux.cfg	Tue Dec 13 20:17:57 2011 +0200
@@ -0,0 +1,21 @@
+# Custom PVL isolinux.cfg for preseed booting
+menu hshift 15
+menu width 49
+
+menu title Installer boot menu
+include stdmenu.cfg
+
+default preseed
+label preseed
+	menu label ^Install (Preseed {GUEST_NAME})
+	menu default
+	kernel /install.amd/vmlinuz
+	append vga=788 initrd=/install.amd/initrd.gz auto=true priority=critical preseed/file=/cdrom/{INSTALL_PRESEED_NAME} preseed/file/checksum={INSTALL_PRESEED_CHECKSUM} -- quiet 
+
+
+
+default vesamenu.c32
+prompt 1
+timeout 20
+
+
--- a/preseed/preseed.cfg	Sat Dec 10 17:06:27 2011 +0200
+++ b/preseed/preseed.cfg	Tue Dec 13 20:17:57 2011 +0200
@@ -40,7 +40,7 @@
 # XXX: this is for asdf.paivola.fi
 d-i netcfg/get_hostname                 string asdf
 d-i netcfg/get_domain                   string paivola.fi
-d-i netcfg/get_ipaddress                string 194.197.235.36
+d-i netcfg/get_ipaddress                string {NET_IPADDR}
 d-i netcfg/get_netmask                  string 255.255.255.0
 d-i netcfg/get_gateway                  string 194.197.235.1
 d-i netcfg/get_nameservers              string 194.197.235.210 194.197.235.252
@@ -138,7 +138,7 @@
 # name must be given in traditional, non-devfs format (so e.g. /dev/hda or
 # /dev/sda, and not e.g. /dev/discs/disc0/disc).
 # For example, to use the first SCSI/SATA hard disk:
-d-i partman-auto/disk string /dev/vda
+d-i partman-auto/disk string {GUEST_DISK}
 
 # In addition, you'll need to specify the method to use.
 # The presently available methods are:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/lib.sh	Tue Dec 13 20:17:57 2011 +0200
@@ -0,0 +1,125 @@
+## library functions
+
+function die () {
+    echo "!!! $@" >&2
+
+    exit 1
+}
+
+# Execute command verbosely, and exit on failure
+function cmd () {
+    echo ">>> $@"
+
+    [ $_MOCK ] && return 0
+
+    eval "$@" # return $?
+}
+
+function expand_MB () {
+    local size=${1^}
+
+    case ${size: -1} in 
+        G)
+            size=$(( ${size%G} * 1024))
+
+            ;;
+    esac
+
+    echo $size
+}
+
+function extract_iso () {
+    iso=$1
+    dst=$2
+
+    [ ! -r "$iso" ] && die "Given .iso is not readable: $iso"
+    [ -z "$dst" ] && die "Must give destination: $dst"
+    [ -e "$dst" ] && die "Given destination already exists: $dst"
+
+    # temporary mount
+    mnt=$(mktemp -d mnt.XXXX)
+
+    # clean on exit
+    function cleanup () {
+        if mountpoint -q $mnt; then
+           sudo umount $mnt
+        fi
+
+        [ -d $mnt ] && rmdir $mnt
+
+        return $1
+    }
+
+    # loop-mount
+    cmd sudo mount -o loop $iso $mnt || cleanup 1
+
+    # copy
+    cmd cp -r $mnt $dst || cleanup 1
+
+    # done, cleanup
+    cleanup 0
+}
+
+function my_md5sum () {
+    /usr/bin/md5sum $1 | (
+        read md5sum path
+        echo $md5sum
+    )
+}
+
+function expand_template () {
+    local tpl=$1
+    local out=$2
+
+    local linecount=0
+
+    # read in each line at a time
+    while IFS='' read -r line; do
+        linecount=$((linecount + 1))
+
+        if [ "${line:0:1}" == "#" ]; then
+            # ignore comments; pass through as-is
+            echo "$line"
+        
+        else
+            # evaluate {...} expressions
+            # a slight hack, but it works \o/
+            # http://stackoverflow.com/questions/415677/how-to-replace-placeholders-in-a-text-file/7633579#7633579
+            line="${line//\\/\\\\}"
+            line="${line//\"/\\\"}"
+            line="${line//\`/\\\`}"
+            line="${line//\$/\\\$}"
+            line="${line//{/\${}"   # This is just for vim: } "
+
+            # echo "($line)" >&2
+            (eval "echo \"$line\"") || die "Error at $tpl:$linecount: $line"
+        fi
+ 
+    done < $tpl > $out
+}
+
+# Recursive expand_template files from src -> dst
+# XXX: not used
+function expand_tree () {
+    local src=$1
+    local dst=$2
+    local filter=${3:-'*'}
+
+    for path in ${src}/${filter}; do
+        local name=$(basename $path)
+        local target=$dst/$name
+
+        if [ -d $path ]; then
+            echo "expand_tree: $path -> $target"
+            echo "expand_tree $path $target $filter"
+
+        elif [ -f $path ]; then
+            echo "expand_file: $path -> $target"
+            echo "expand_file $path $target"
+
+        else
+            echo "XXX: ignore weird file: $path"
+
+        fi
+    done
+}