#!/bin/bash source testboot.conf # defaults topdir=${topdir:-/opt/testboot} dir=${dir:-$topdir} dracutdir=${dracutdir:-$topdir/src/dracut} anacondadir=${anacondadir:-$topdir/src/anaconda} ram=${ram:-768} disk=${disk:-$dir/disk.img} disk2=${disk2:-$dir/disk2.img} cdrom=${cdrom:-$dir/iso/Fedora-17-x86_64-DVD.iso} graphics=${graphics:-vnc} dracut_opts="${dracut_opts:---add anaconda --omit plymouth}" network="${network:-default}" vmname="${vmname:-testboot}" compress=${compress:-$(type -P pigz || type -P xz)} rebuild="${rebuild:-false}" [ "$compress" = "xz" ] && compress="xz --check-crc32 -1" printhelp() { cat << __EOT__ Usage: $(basename $0) [OPTION...] [KERNEL ARGS...] Boot a Fedora(ish) iso in a VM with the given kernel args. -h, --help show this help -m, --ram=RAM create VM with this much ram (in MB) -c, --virtconsole add a virtual console device (hvc0) -s, --serialconsole add a serial console device (ttyS0) -t, --text create VM with no graphics (console output on-screen) -d, --fromcd boot from the CDROM device --nocd don't attach the CDROM device --dualnic create VM with two NICs --nonic create VM with no NICs Edit testboot.conf to configure the paths and the ISO to use. __EOT__ } usecd="true" usenet="true" ARGS=$(getopt --options "hdcsrtm:" \ --longoptions "help,fromcd,nocd,virtconsole,serialconsole,text,dualnic,nonic,rebuild,ram:"\ --name testboot.sh \ -- "$@") || exit 1 eval set -- "$ARGS" while :; do case "$1" in -h|--help) printhelp; exit 0;; -d|--fromcd) fromcd="true"; shift;; --nocd) usecd=""; shift;; --dualnic) dualnic="true"; shift;; --nonic) dualnic=""; usenet=""; nonet="true"; shift;; -c|--virtconsole) console="--console pty"; shift;; -s|--serialconsole) console="--serial pty"; shift;; -t|--text) graphics="none"; shift;; -m|--ram) ram="$2"; shift 2;; -r|--rebuild) rebuild="true"; shift;; --) shift; break;; *) echo "getopt parse error"; exit 1 ;; esac; done if [ ! -f $cdrom ]; then echo "Can't find cdrom!" exit 1 fi [ $(id -u) = 0 ] || { echo "be root."; exit 1; } chcon -t virt_content_t $cdrom initrd_unpack() { local cat=cat img="$1" outdir="$2" case `file $1` in *:\ gzip*) cat=zcat ;; *:\ xz*|*:\ XZ*) cat=xzcat ;; esac rm -rf $outdir $outdir.tmp; mkdir -p $outdir.tmp ( cd $outdir.tmp ; $cat $img | cpio -iumd 2>/dev/null ) mv $outdir.tmp $outdir } get_modules() { echo -n "finding kernel version..." moddir=$(find $1 -name "modules.dep") moddir=${moddir%/modules.dep} kv=${moddir##*/} echo "$kv" | tee $dir/vmlinuz.kv if [ ! -d /lib/modules/$kv ]; then echo -n "getting modules..." cp -a $moddir /lib/modules/$kv echo "done" fi } apply_updates() { ( cd $dir/updates find . -depth -type d | while read d; do [ ! -d "../initramfs/$d" ] && mkdir -p "../initramfs/$d" done find . -depth \! -type d | while read f; do cp -a "$f" "../initramfs/$f" echo " ${f#.}" done ) } initrd_cpio() { ( cd $dir/initramfs; find . | cpio -co ) 2>/dev/null } # TODO: check for $dracutdir/dracut.sh and git pull otherwise setup_dracut() { if [ ! -f $dracutdir/modules.d/80anaconda/parse-kickstart ]; then if [ ! -d $anacondadir/dracut ]; then # TODO: git pull echo "ERROR: can't find anaconda dracut module :/" exit 1 else ln -s $anacondadir/dracut $dracutdir/modules.d/80anaconda fi fi } grab_kernel_and_initrd() { local cdrom="$1" kernel="$2" initrd="$3" mnt="$dir/.mnt" umount $mnt &>/dev/null mkdir -p $mnt mount -o ro,loop $cdrom $mnt || { echo "failed to mount cdrom!"; exit 1; } cp -f $mnt/isolinux/vmlinuz $kernel cp -f $mnt/isolinux/initrd.img $initrd umount $mnt rmdir $mnt } if [ "$fromcd" != "true" ]; then kernel_args="$@" # check RAM if [ "$ram" -lt 768 ]; then kernel_args="$* inst.memcheck=0" echo "adding inst.memcheck=0 to kernel args" fi # do we need to pull out the kernel/modules? vmlinuz="$dir/vmlinuz" [ -e $vmlinuz.kv ] && kv=$(< $vmlinuz.kv) if [ $cdrom -nt $vmlinuz -o -z "$kv" -o ! -d /lib/modules/$kv ]; then echo "getting kernel and modules" grab_kernel_and_initrd $cdrom $vmlinuz $dir/initrd.img.orig initrd_unpack $dir/initrd.img.orig $dir/initramfs.orig get_modules $dir/initramfs.orig # sets $kv # force rebuild of initrd.img rm -rf $dir/initramfs fi # do we need to create the initramfs dir? initrd="$dir/initrd.img" if [ ! -d $dir/initramfs ]; then if [ "$rebuild" == "true" ]; then echo "rebuilding initramfs" setup_dracut ( cd $dracutdir ./dracut.sh --local --no-compress --nomdadmconf --nolvmconf \ --prefix /run/initramfs $dracut_opts \ --force $dir/.initrd.cpio $kv ) || exit 1 initrd_unpack $dir/.initrd.cpio $dir/initramfs cp $dir/initramfs.orig/.buildstamp $dir/initramfs/.buildstamp # force rebuild of initrd.img rm -rf $initrd else echo "copying initramfs" cp -a $dir/initramfs.orig $dir/initramfs fi fi # do we need to build initrd.img from initramfs? if [ ! -e $initrd ] || \ find initramfs updates -newer $initrd | grep -q .; then if [ -d updates ]; then echo "applying updates to initramfs" apply_updates fi echo "making initrd.img" initrd_cpio | $compress -c > $dir/.initrd.tmp || exit 1 mv -f $dir/.initrd.tmp $initrd fi bootarg="kernel=$vmlinuz,initrd=$initrd,kernel_args=$kernel_args" fi echo "Creating '$vmname' guest..." virsh destroy $vmname &>/dev/null virsh undefine $vmname &>/dev/null virt-install --name $vmname --ram $ram --graphics $graphics \ --os-type linux --os-variant fedora16 $console \ --disk $disk,size=10 --disk $disk2,size=10 \ ${nonet:+--nonetworks} \ ${usenet:+--network network=$network,model=virtio,mac=52:54:00:03:31:38} \ ${dualnic:+--network network=$network,model=virtio,mac=52:54:00:03:31:39} \ ${usecd:+--disk $cdrom,device=cdrom} \ ${bootarg:+--boot "$bootarg"} virsh destroy $vmname &>/dev/null # historical interest: this is how it'd work in qemu do_qemu() { echo "starting qemu" echo "C-a x to exit, C-a c for console monitor" qemu-kvm -m $ram -kernel $kernel -initrd $initrd \ -cdrom $cdrom -nographic -append $kernel_args }