Skip to content

Commit

Permalink
proto typing image building script.
Browse files Browse the repository at this point in the history
  • Loading branch information
Masahiro Fujiwara committed Nov 11, 2015
1 parent f77b6b3 commit 532de19
Show file tree
Hide file tree
Showing 20 changed files with 682 additions and 0 deletions.
2 changes: 2 additions & 0 deletions vmimages/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
packer/
packer_cache/
8 changes: 8 additions & 0 deletions vmimages/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Building Image

Run the ``build.sh`` with target OS name that you want.

```
$ ./build.sh centos-7.1-x86_64
```

120 changes: 120 additions & 0 deletions vmimages/README.qemu-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# qemu-build

``qemu-build`` is an image building script inspired by packer-qemu driver.
This program run the following tasks. Similar to ``packer`` but it is more simplified.

1. Download iso image from remote site.
2. Run ``qemu`` with the .iso and FD image and boot installer from the .iso.
3. Send boot command to console then the unattended install is kicked.
Configuration files for the installer are supplied from FD image.
4. Shutdown ``qemu`` from guest once all done.

## How to use

Basic usage:

```
% qemu-build build.conf
```

``build.conf`` has set of shell variables to build new OS image from iso installer.

```
target_image=centos7.img
kickstart_file="ks.cfg"
iso_checksum="d07ab3e615c66a8b2e9a50f4852e6a77"
iso_urls=(
http://ftp.riken.jp/Linux/centos/7.1.1503/isos/x86_64/CentOS-7-x86_64-Minimal-1503-01.iso
)
# "<tab>text<space>ks=hd:fd0:/ks.cfg"
boot_commands=(tab t e x t spc k s equal h d shift-semicolon f d 0 shift-semicolon slash k s dot c f g ret)
qemu_args="-m 1G"
post_scripts=(./post-scripts/*.sh)
```

```
# yum install -y $(qemu-build --show-deps)
```

## Config Parameters

Path information is calculated from the location of config file.

Required:

``iso_checksum``

``iso_urls`` is shell array to supply the list of OS installer image file on remote site. It continues to
try next urls until fetching succeeds.

``install_iso`` is path string to the installer image which you already have. ``iso_urls`` is skipped if this
parameter is set.

``target_image`` the path to image file to generate.

Optional:

``kickstart_file`` the file is copied to FD image.

``boot_commands`` are sent to qemu guest over ``sendkey`` monitor interface while the OS installer prompts
and waits for typing keys. ``sendkey`` emulates keyboard so it can only pass one character at a time. See
the sendkey character list pasted from ``qemu``.

``qemu_args`` extra command options for ``qemu`` if you need.

``qemu_binary`` path to ``qemu`` binary.

``post_scripts`` an array of script path(s) to run at post stage in qemu guest. The files are just copied
to FD image. unattended installation must be organized to call them.

``local_scripts`` an array of command line which run at qemu host. They are called after sending ``boot_commands``
so helps to handle post process on host side until the installation completes.


### Local Script

Bundled local scripts:

``screen-watch`` monitors qemu screen updates. It supports
to detect if updates happens within a period time and kill
qemu if the installation process is likely to be stopped.

``alt-b`` is just sends alt-b key sequence to qemu. It is
useful to signal CentOS graphical installer to proceed.


### ``sendkey`` character table


```
# discover the supported keys by doing:
# telnet 127.0.0.1 4567
# sendkey <tab>
# Here is the result:
(qemu) sendkey
0 1 2 3 4
5 6 7 8 9
a again alt alt_r altgr
altgr_r apostrophe asterisk b backslash
backspace bracket_left bracket_right c caps_lock
comma compose copy ctrl ctrl_r
cut d delete dot down
e end equal esc f
f1 f10 f11 f12 f2
f3 f4 f5 f6 f7
f8 f9 find front g
grave_accent h help home i
insert j k kp_0 kp_1
kp_2 kp_3 kp_4 kp_5 kp_6
kp_7 kp_8 kp_9 kp_add kp_decimal
kp_divide kp_enter kp_multiply kp_subtract l
left less lf m menu
meta_l meta_r minus n num_lock
o open p paste pause
pgdn pgup print props q
r ret right s scroll_lock
semicolon shift shift_r slash spc
stop sysrq t tab u
undo unmapped up v w
x y z
```
26 changes: 26 additions & 0 deletions vmimages/bin/alt-b
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

# NOTE: Sometimes all the keys above are typed OK and the ks.cfg file
# is read in OK, but the installation does not start until the user
# clicks on the "Begin" button. One possible cause could be the VNC
# windows being open and some UI events being sent to the graphical
# installer, which senses the human there and politely asks for
# confirmation.

# Update: Nope. Did not work even with no vncviewer connected. Looks like
# alt-B will select that button. Seems to take at least 20 seconds to get
# to that screen so....

if [[ $# -eq 1 ]];
sleep $1
else
sleep 60
fi

echo sendkey alt-b | nc 127.0.0.1 4567

echo
echo "Just sent an extra alt-b just in case"
echo "it is stuck on the confirm install screen"
echo

192 changes: 192 additions & 0 deletions vmimages/bin/qemu-build
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#!/bin/bash

set -e -o pipefail

# Environment variables
ISO_CACHE_DIR=${ISO_CACHE_DIR:-"."}

# Configuration parameters in .conf.
install_iso=
kickstart_file=
target_image=
qemu_binary="qemu-kvm"
iso_checksum_type="md5"
iso_checksum=
declare -a iso_urls=()
declare -a boot_commands=
declare -a post_scripts=()
declare -a local_scripts=()

# option parameters
is_overwrite_image=

reportfailed()
{
echo "Script failed...exiting. ($*)" 1>&2
exit 255
}

usage_deps() {
cat <<END
qemu-img qemu-kvm mtools dosfstools nc curl
END
}

usage() {
cat <<END
$(basename $0) [options] <conf>
Options:
--force,-f : Overwrite existing image file.
Install dependencies:
yum install -y \$($0 --show-deps)
END
}

while [[ $# -gt 0 ]]; do
case $1 in
--help|-h)
usage
exit
;;
--show-deps)
usage_deps
exit
;;
--force|-f)
is_overwrite_image=1
shift
;;
*)
break
;;
esac
done

# Load .conf
if [[ $# -eq 1 && -f $1 ]]; then
CONF_PATH=$1
shopt -s nullglob
. $CONF_PATH
shopt -u nullglob
else
reportfailed "Unknown conf path: $1"
fi

cd $(dirname $CONF_PATH)

# Minimal parameter checking to catch typos:
if [[ -z $install_iso ]]; then
[[ -n $iso_checksum ]] || reportfailed "iso_checksum not found."
[[ -n $iso_checksum_type ]] || reportfailed "iso_checksum_type not found."

if [[ -f "${ISO_CACHE_DIR}/${iso_checksum}.iso" ]]; then
install_iso="${ISO_CACHE_DIR}/${iso_checksum}.iso"
else
for u in ${iso_urls[@]}
do
curl --show-error -L -o "${ISO_CACHE_DIR}/${iso_checksum}.iso" "$u"
if [[ $? -eq 0 ]]; then
sum_val=$("${iso_checksum_type}sum" "${ISO_CACHE_DIR}/${iso_checksum}.iso" | cut -f 1 -d ' ')
if [[ "${sum_val}" == "${iso_checksum}" ]]; then
install_iso="${ISO_CACHE_DIR}/${iso_checksum}.iso"
break
else
rm -f "${ISO_CACHE_DIR}/${iso_checksum}.iso"
fi
fi
done
fi
fi
[ -f "$install_iso" ] || reportfailed "Iso ($install_iso) not found."

[ -f "$kickstart_file" ] || reportfailed " ($kickstart_file) not found."

if [[ -z "$is_overwrite_image" ]]; then
[ -f "$target_image" ] && reportfailed "$target_image already exists"
fi

# Make sure it is writable
touch "$target_image" || reportfailed "Could not create '$target_image' (the third parameter)"

TARGET_DIR="$(cd "$(dirname "$(readlink -f "$target_dir")")" && pwd -P)" || reportfailed

WORK_DIR=$(mktemp -d)
trap "rm -rf $WORK_DIR" EXIT

# Variables can be referenced from child processes.
export WORK_DIR CONF_PATH TARGET_DIR KVM_PID

(
rm -f "$target_image"
qemu-img create -f qcow2 "$target_image" 10000M
) || reportfailed "Problem while creating empty qcow2 image"

KSFPY="$WORK_DIR/kickstart_floppy.img"

(
dd if=/dev/zero of="$KSFPY" count=1440 bs=1k
/sbin/mkfs.msdos "$KSFPY"
if [[ -f $kickstart_file ]]; then
mcopy -i "$KSFPY" "$kickstart_file" ::/ks.cfg
fi
if [[ ${#post_scripts} -gt 0 ]]; then
for src in ${post_scripts[@]}
do
mcopy -i "$KSFPY" "$src" ::/$(basename $src)
done
fi
mdir -i "$KSFPY"
) || reportfailed "Problem while creating floppy with kickstart file"


kvmcmdline=(
$qemu_binary
-name ksvm

-fda "$KSFPY"
-drive "file=$target_image,if=virtio,cache=writeback,discard=ignore"

-machine type=pc,accel=kvm

-netdev user,id=user.0,hostfwd=tcp::2224-:22
-device virtio-net,netdev=user.0
-monitor telnet:0.0.0.0:4567,server,nowait
-vnc 0.0.0.0:47
$qemu_args
)

#echo "${kvmcmdline[@]}" >runscript.sh
#chmod +x runscript.sh

echo "${kvmcmdline[@]}" -boot once=d -cdrom "$install_iso"
if ! type $qemu_binary > /dev/null 2>&1; then
reportfailed "Not found $qemu_binary"
fi
"${kvmcmdline[@]}" -boot once=d -cdrom "$install_iso" >"$WORK_DIR/kvm.stdout" 2>"$WORK_DIR/kvm.stderr" &
KVM_PID=$!
echo "$KVM_PID" >"$WORK_DIR/kvm.pid"
echo "Qemu launched ($KVM_PID)"

sleep 15

if [[ ${#boot_commands} -gt 0 ]]; then
echo "Sending boot command..."
echo ${boot_commands[@]}
for k in ${boot_commands[@]}
do
echo sendkey $k
done | nc 127.0.0.1 4567 > $WORK_DIR/boot_command.log
fi

if [[ ${#local_scripts} -gt 0 ]]; then
for i in "${local_scripts[@]}"
do
echo "Local script: $i"
$i
done
fi

echo "Now waiting for kvm to exit. (FYI, ^c will kill KVM)"
wait
Loading

0 comments on commit 532de19

Please sign in to comment.