diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README | 32 | ||||
-rw-r--r-- | TODO | 18 | ||||
-rwxr-xr-x | di-maker | 30 | ||||
-rwxr-xr-x | kvm-creator | 75 | ||||
-rwxr-xr-x | kvm-manager | 81 |
6 files changed, 237 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ @@ -0,0 +1,32 @@ +KVM-Manager + +Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net> +Date: 2009-10-08 11:22:14-0400 + +This is a small set of scripts to make it relatively easy to manage a +stable of kvm instances in a fairly secure and isolated fashion. + +The basic model is to use runit to supervise each KVM instance, with a +single, non-privileged user account for each instance. + +A typical workflow to start an installer is: + +kvm-creator create $GUESTNAME [$DISKSIZE [$RAM [$TAP [$MAC] ] ] ] +# set up boot media for the host ("put the installer CD in the drive"): +ln -s /usr/local/share/ISOs/d-i.iso /home/$GUESTNAME/vms/$GUESTNAME/cd.iso +# set up access to the account: +mkdir -p /home/$GUESTNAME/.ssh +cat ~/.ssh/authorized_keys >> /home/$GUESTNAME/.ssh/authorized_keys +# start up the host +update-service --add /etc/sv/kvm/$GUESTNAME + + +To access the guest's serial console, do: + + ssh -t $GUESTNAME@host.machine screen -x $GUESTNAME + + +trouble getting a serial console-enabled debian +installer ISO? try using the di-maker script. + +All patches, fixes, suggestions welcome! @@ -0,0 +1,18 @@ +TODO for KVM-Manager +-------------------- + +(much) better documentation + +file re-organization/restructuring + +debian packaging? + +more flexibility with networking (currently only supports + tun/tap-style bridging) + +/usr/local/sbin is hard-coded in places (e.g. in the run and finish + scripts); it probably shouldn't be. + +screen logging is still sub-par, and could potentially fill the host + disks if the kernel spew is immense -- rotate? filter through + svlogd somehow? same problem as cereal. diff --git a/di-maker b/di-maker new file mode 100755 index 0000000..d6ad5f3 --- /dev/null +++ b/di-maker @@ -0,0 +1,30 @@ +#!/bin/bash + +# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# Date: 2009-10-08 +# License: GPL v3+ + +set -e + +# depends on grub2 -- should probably be refactored to use +# grub-mkrescue + +WORKDIR=$(mktemp -d) + +( cd "$WORKDIR" && wget http://ftp.nl.debian.org/debian/dists/lenny/main/installer-amd64/current/images/netboot/debian-installer/amd64/{linux,initrd.gz} ) + +mkdir -p "$WORKDIR/boot/grub" + +cp /usr/lib/grub/x86_64-pc/stage2_eltorito "$WORKDIR/boot/grub/" +cat > "$WORKDIR/boot/grub/menu.lst" <<EOF +serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 +terminal serial + +title lenny d-i (created $(date -R)) +kernel /linux -- console=ttyS0,115200n8 +initrd /initrd.gz +EOF + +genisoimage -R -input-charset utf-8 -b boot/grub/stage2_eltorito -no-emul-boot --boot-load-size 4 -boot-info-table "$WORKDIR" + +rm -rf "$WORKDIR" diff --git a/kvm-creator b/kvm-creator new file mode 100755 index 0000000..6ea989f --- /dev/null +++ b/kvm-creator @@ -0,0 +1,75 @@ +#!/bin/bash +set -x + +# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# Date: 2009-10-08 +# License: GPL v3+ + +CMD="$1" +shift + +NAME="$1" +SIZE="${2:-3G}" +RAM="${3:-512}" +TAP="${4:-$(( $( cat /etc/sv/kvm/*/env/TAP | sed 's/^tap//' | sort -n | tail -n 1 ) + 1 ))}" +MAC="${5:-$(cat /etc/sv/kvm/*/env/MAC | head -n1 | cut -f 1-5 -d: ):$(( $( cat /etc/sv/kvm/*/env/MAC | cut -f 6 -d: | sort -n | tail -n 1 ) + 1 ))}" + +VG=vg_malty0 + +destroy() { + + update-service --remove "/etc/sv/kvm/$NAME" + rm -rf "/etc/sv/kvm/$NAME" + deluser "$NAME" + lvremove "$VG/$NAME" + rm -rf "/home/$NAME" + +} + +create() { + set -e + +# FIXME: check that this stuff doesn't exist yet: + + adduser "$NAME" --disabled-password --gecos "$NAME KVM user,,," + mkdir "/home/$NAME/"{.ssh,vms,"vms/$NAME"} + touch "/home/$NAME/vms/$NAME/netboot" + chown "$NAME:$NAME" "/home/$NAME/"{.ssh,vms,"vms/$NAME","vms/$NAME/netboot"} + cp /root/.ssh/authorized_keys "/home/$NAME/.ssh/" + lvcreate --name "$NAME" --size "$SIZE" $VG + mkdir "/etc/sv/kvm/$NAME"{,/log,/env} + cat > "/etc/sv/kvm/$NAME/log/run" <<EOF +#!/bin/sh + +exec 2>&1 +exec chpst -e ../env /usr/local/sbin/kvm-manager log +EOF + cat > "/etc/sv/kvm/$NAME/run" <<EOF +#!/bin/sh + +exec 2>&1 +exec chpst -e ./env /usr/local/sbin/kvm-manager up +EOF + cat > "/etc/sv/kvm/$NAME/finish" <<EOF +#!/bin/sh + +exec 2>&1 +exec chpst -e ./env /usr/local/sbin/kvm-manager down +EOF + chmod a+x "/etc/sv/kvm/$NAME/"{run,finish,log/run} + echo "$NAME" > "/etc/sv/kvm/$NAME/env/OWNER" + echo "$NAME" > "/etc/sv/kvm/$NAME/env/VMNAME" + echo "$TAP" > "/etc/sv/kvm/$NAME/env/TAP" + echo "$RAM" > "/etc/sv/kvm/$NAME/env/RAM" + echo "$MAC" > "/etc/sv/kvm/$NAME/env/MAC" + +} + +demo() { + + for foo in NAME TAP RAM MAC SIZE ; do + echo "$foo : ${!foo}" + done +} + +"$CMD" diff --git a/kvm-manager b/kvm-manager new file mode 100755 index 0000000..40972ce --- /dev/null +++ b/kvm-manager @@ -0,0 +1,81 @@ +#!/bin/sh + +set -e +set -x + +# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# Date: 2009-10-08 +# License: GPL v3+ + +## expect to pull these values from the environment: +# VMNAME=snapper +# OWNER=jrollins +# TAP=tap0 +# RAM=512 +# MAC=52:54:00:12:34:56 + +if [ -z "$VMNAME" ] ; then + exit 1 +fi + +################### +OWNERGROUP=$(groups "$OWNER" | cut -f1 -d\ ) +OWNERHOME=$(getent passwd "$OWNER" | cut -f6 -d: ) + +VGNAME=vg_$(hostname)0 + +up() { +# bring up the network tap: + modprobe -v tun + tunctl -u "$OWNER" -t "$TAP" + ip link set "$TAP" up + brctl addif br0 "$TAP" + +# make sure the block device is readable by the owner: + chgrp "$OWNERGROUP" "/dev/mapper/${VGNAME}-$VMNAME" + + chpst -u "$OWNER:$OWNERGROUP" mkdir -p "$OWNERHOME/vms/$VMNAME" + + CDISO="$OWNERHOME/vms/$VMNAME/cd.iso" + NETBOOT="$OWNERHOME/vms/$VMNAME/netboot" + KVMARGS= + + if [ -e "$NETBOOT" ] ; then + KVMARGS="-boot n" + elif [ -e "$CDISO" ] && [ -e $(readlink -f "$CDISO") ] ; then + KVMARGS="-cdrom $CDISO -boot d" + fi + + LOGNAME="$OWNERHOME/vms/$VMNAME/console" + ln -sfT "$LOGNAME" ./servicelog + if [ -e "$LOGNAME" ] ; then + chpst -u "$OWNER" mv "$LOGNAME" "$LOGNAME".$(date +%F_%T%z|tr : .) + fi + + exec chpst -u "$OWNER:$OWNERGROUP:kvm" /usr/bin/screen -D -m -L -c /etc/screenrc.kvm-manager -S "$VMNAME" -t "$VMNAME" -s /bin/false /usr/bin/kvm $KVMARGS -nographic -name "$VMNAME" -m "$RAM" -net nic,"macaddr=$MAC" -net "tap,hostname=$VMNAME,ifname=$TAP,script=no,downscript=no" -no-reboot -serial stdio "/dev/mapper/${VGNAME}-$VMNAME" +} + + +down() { + brctl delif br0 "$TAP" + ip link set "$TAP" down + tunctl -d "$TAP" +# no need to lock up the block device as well, since the owner might +# prefer to manipulate the disk directly. +} + +log() { + LOGDIR="$OWNERHOME/vms/$VMNAME/servicelog" + chpst -u "$OWNER" mkdir -p "$LOGDIR" + exec chpst -u "$OWNER" svlogd -tt "$LOGDIR" +} + +case "$1" in + up|down|log) + "$1" + ;; + *) + echo "Usage: $0 [up|down]" + exit 1 + ;; +esac |