diff options
Diffstat (limited to 'kvmx')
-rwxr-xr-x | kvmx | 358 |
1 files changed, 284 insertions, 74 deletions
@@ -1,66 +1,56 @@ #!/bin/bash # -# KVM and SPICE client wrapper +# KVMX Manager. # -# Parameters +# Basic parameters BASENAME="`basename $0`" DIRNAME="`dirname $0`" -STORAGE="/var/cache/qemu" -SHARED="/var/data/load" -PORT="$(($RANDOM + 1024))" -SSH="$(($PORT + 22))" ACTION="$1" VM="$2" -BOX="$STORAGE/$VM/box.img" -PIDFILE="$STORAGE/$VM/pid" -PORTFILE="$STORAGE/$VM/port" -SSHFILE="$STORAGE/$VM/ssh" -SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=FATAL -i $DIRNAME/ssh/insecure_private_key" -LOGIN="user" +GLOBAL_USER_CONFIG_FOLDER="$HOME/.config/kvmx" # Run spice client -function kvmx_spice_client { - # https://lists.freedesktop.org/archives/spice-devel/2013-September/014643.html - SPICE_NOGRAB=1 spicec --host localhost --port $PORT & - #spicy -h localhost -p $PORT - #remote-viewer spice://localhost:$PORT +function kvmx_spice { + if [ "$run_spice_client" == "1" ]; then + # https://lists.freedesktop.org/archives/spice-devel/2013-September/014643.html + SPICE_NOGRAB=1 spicec --host localhost --port $PORT & + #spicy -h localhost -p $PORT + #remote-viewer spice://localhost:$PORT - # Give time to boot - sleep 5 + # Give time to boot + sleep 5 - # Fix window titles - xdotool search --name "SPICEc:0" set_window --name $VM -} - -# Restart vdagent inside the guest -function kvmx_clip { - instances="`ps -o pid,command -e | grep "spice-vdagent$" | cut -d ' ' -f 2 | xargs`" - - # Kill old instances - for pid in $instances; do - kill -9 $pid &> /dev/null - done - - # Just to make sure we're inside a virtual machine - if which spice-vdagent &> /dev/null ; then - spice-vdagent + # Fix window titles + if which /usr/bin/xdotool &> /dev/null; then + xdotool search --name "SPICEc:0" set_window --name $VM + fi fi } # Bring virtual machine up function kvmx_up { - # FIXME - # Check if machine is up + if kvmx_running; then + echo "$BASENAME: guest $VM is already running" + exit 1 + fi + + if [ "$shared_folder" ]; then + local shared="-fsdev local,id=shared,path=$shared_folder,security_model=none -device virtio-9p-pci,fsdev=shared,mount_tag=shared" + fi + + # Check if image exists, create otherwise + if [ ! -e "$image" ]; then + kvmx-create $GLOBAL_USER_CONFIG_FOLDER/$VM + fi # Run virtual machine - kvm -m 2048 -name $VM -drive file=$BOX,if=virtio -vga qxl \ + kvm -m 2048 -name $VM -drive file=$image,if=virtio -vga qxl $shared \ -spice port=$PORT,addr=127.0.0.1,disable-ticketing,streaming-video=off,jpeg-wan-compression=never,playback-compression=off,zlib-glz-wan-compression=never,image-compression=off \ -device virtio-serial-pci \ -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 \ -chardev spicevmc,id=spicechannel0,name=vdagent \ - -smp 2 -soundhw ac97 -cpu host -balloon virtio \ - -fsdev local,id=shared,path=$SHARED,security_model=none -device virtio-9p-pci,fsdev=shared,mount_tag=shared \ + -smp 2 -soundhw ac97 -cpu host -balloon virtio \ -net nic,model=virtio \ -net user,hostfwd=tcp:127.0.0.1:$SSH-:22 & @@ -71,50 +61,270 @@ function kvmx_up { echo $PORT > $PORTFILE echo $SSH > $SSHFILE - kvmx_spice_client + kvmx_spice } -# Check -if [ -z "$VM" ] && [ "$ACTION" != "clip" ]; then - echo "usage: $BASENAME <action> <vm>" - exit 1 -elif [ ! -e "$BOX" ] && [ "$ACTION" != "clip" ]; then - echo "file not found: $BOX" +# Display usage +function kvmx_usage { + echo "usage: $BASENAME <action> [options]" + echo "examples:" + echo "" + echo "$BASENAME list" + echo "$BASENAME init <machine> [folder]" + echo "$BASENAME clone <orig> <dest>" + exit 1 -fi +} -# TODO: check for a ~/.kvmx config -# TODO: check for a kvmxfile +# Log into the guest using SSH +function kvmx_ssh { + if ! kvmx_running; then + echo "$BASENAME: guest $VM is not running" + exit 1 + fi + + shift 2 + SSH="`cat $SSHFILE`" + $SSH_COMMAND -p $SSH $SSH_LOGIN@127.0.0.1 $* +} + +# Suspend the virtual machine +function kvmx_suspend { + if ! kvmx_running; then + echo "$BASENAME: guest $VM is not running" + exit 1 + fi -# Dispatch -if [ "$ACTION" == "up" ]; then - kvmx_up -elif [ "$ACTION" == "clip" ]; then - kvmx_clip -elif [ "$ACTION" == "suspend" ]; then PID="`cat $PIDFILE`" kill -STOP $PID -elif [ "$ACTION" == "resume" ]; then +} + +# Check if a guest is running +function kvmx_running { + if [ ! -e "$PIDFILE" ]; then + return 1 + fi + + PID="`cat $PIDFILE`" + ps $PID &> /dev/null + + return $? +} + +# Resume the guest +function kvmx_resume { + if ! kvmx_running; then + echo "$BASENAME: guest $VM is not running" + exit 1 + fi + PID="`cat $PIDFILE`" kill -CONT $PID -elif [ "$ACTION" == "poweroff" ]; then - echo TODO -elif [ "$ACTION" == "ssh" ]; then - shift 2 - SSH="`cat $SSHFILE`" - $SSH_COMMAND -p $SSH $LOGIN@127.0.0.1 $* -elif [ "$ACTION" == "rsync" ]; then +} + +# Poweroff the guest +function kvmx_poweroff { + kvmx_ssh /usr/bin/sudo poweroff +} + +# Rsync files to the guest +function kvmx_rsync { + if ! kvmx_running; then + echo "$BASENAME: guest $VM is not running" + exit 1 + fi + ORIG="$3" DEST="$4" SSH="`cat $SSHFILE`" - rsync -av "$SSH_COMMAND -p $SSH" $ORIG/ $LOGIN@127.0.0.1:$DEST/ -elif [ "$ACTION" == "provision" ]; then - echo TODO -elif [ "$ACTION" == "create" ]; then - echo TODO -elif [ "$ACTION" == "init" ]; then - # TODO: copy from template - touch .kvmxfile -elif [ "$ACTION" == "upgrade" ]; then - echo TODO + rsync -av "$SSH_COMMAND -p $SSH" $ORIG/ $SSH_LOGIN@127.0.0.1:$DEST/ +} + +# List guests +function kvmx_list { + ls $GLOBAL_USER_CONFIG_FOLDER +} + +# Upgrade guest +function kvmx_upgrade { + echo "sudo apt-get update && sudo apt-get dist-upgrade -y && sudo apt-get autoremove -y" | kvmx_ssh +} + +# Initialize +function kvmx_initialize { + if [ "$ACTION" == "init" ] || [ "$ACTION" == "list" ]; then + return + fi + + if [ -z "$VM" ]; then + VM="$(basename `pwd`)" + fi + + # Default parameters + PORT="$(($RANDOM + 1024))" + SSH="$(($PORT + 22))" + SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=FATAL -i $DIRNAME/ssh/insecure_private_key" + SSH_LOGIN="user" + + # Initalize + mkdir -p $GLOBAL_USER_CONFIG_FOLDER + + # Load and check guest config + if [ "$ACTION" != "init" ] && [ "$ACTION" != "list" ] && [ "$ACTION" != "edit" ]; then + if [ ! -e "$GLOBAL_USER_CONFIG_FOLDER/$VM" ]; then + echo "$BASENAME: config not found: $GLOBAL_USER_CONFIG_FOLDER/$VM" + exit 1 + else + source $GLOBAL_USER_CONFIG_FOLDER/$VM + fi + + if [ -z "$image" ]; then + image="/var/cache/qemu/$VM/box.img" + fi + + if [ -z "$KVMXFILE" ]; then + KVMXFILE="/var/cache/qemu/$VM/kvmxfile" + fi + + # Box and folder config + STORAGE="`dirname $image`" + STATE_DIR="$STORAGE/state" + PIDFILE="$STATE_DIR/pid" + PORTFILE="$STATE_DIR/port" + SSHFILE="$STATE_DIR/ssh" + mkdir -p $STATE_DIR + + if [ ! -e "$image" ] && [ "$ACTION" != "up" ]; then + echo "$BASENAME: file not found: $image" + exit 1 + fi + fi +} + +# Initializes a new guest +function kvmx_init { + FOLDER="$3" + + if [ -z "$VM" ]; then + VM="$(basename `pwd`)" + fi + + if [ -e "$GLOBAL_USER_CONFIG_FOLDER/$VM" ]; then + echo "$BASENAME: guest $VM already exists" + exit 1 + fi + + if [ -z "$FOLDER" ]; then + FOLDER="." + fi + + if [ ! -d "$FOLDER" ]; then + mkdir -p $FOLDER + fi + + # Ensure we have an absolute folder name + FOLDER="`cd $FOLDER &> /dev/null && pwd`" + + # Copy config from template + if [ ! -e "$FOLDER/kvmxfile" ]; then + cp $DIRNAME/kvmxfile $FOLDER/ + fi + + # Create config entry + ( cd $GLOBAL_USER_CONFIG_FOLDER && ln -s $FOLDER/kvmxfile $VM ) +} + +# Clone a guest +function kvmx_clone { + if kvmx_running; then + echo "$BASENAME: orig $VM is running, cannot clone." + exit 1 + fi + + FOLDER="$3" + DEST="`basename $FOLDER`" + + if [ -z "$FOLDER" ]; then + kvmx_usage + fi + + # Check if dest machine exists + if [ -e "$GLOBAL_USER_CONFIG_FOLDER/$DEST" ]; then + echo "$BASENAME: destination guest $DEST already exists." + exit 1 + fi + + if [ -d "$FOLDER" ]; then + echo "$BASENAME: destination $FOLDER already exists." + exit 1 + fi + + # Ensure we have an absolute folder name + mkdir -p $FOLDER + FOLDER="`cd $FOLDER &> /dev/null && pwd`" + rmdir $FOLDER + + # Copy image and configuration + cp -r `dirname $image` $FOLDER/ + cp $GLOBAL_USER_CONFIG_FOLDER/$VM $GLOBAL_USER_CONFIG_FOLDER/$DEST + + # Update config file + new_image="$FOLDER/`basename $image`" + sed -i -e "s|image=\"$image\"|image=\"$new_image\"|g" $GLOBAL_USER_CONFIG_FOLDER/$DEST +} + +# Edit guest config +function kvmx_edit { + if [ -z "$EDITOR" ]; then + EDITOR="vi" + fi + + if [ -e "$GLOBAL_USER_CONFIG_FOLDER/$VM" ]; then + $EDITOR $GLOBAL_USER_CONFIG_FOLDER/$VM + else + echo "$BASENAME: $GLOBAL_USER_CONFIG_FOLDER/$VM: file not found." + fi +} + +# Stop a guest +function kvmx_stop { + if kvmx_running; then + PID="`cat $PIDFILE`" + kill $PID + fi +} + +# Destroy a guest +function kvmx_destroy { + kvmx_stop + + #rm -f $image + rm -f $PIDFILE + rm -f $SSHFILE + rm -f $PORTFILE + + echo "$BASENAME: please inspect and remove `dirname $image` manually." +} + +# Purge a guest and all its configuration +function kvmx_purge { + kvmx_destroy + rm -f $GLOBAL_USER_CONFIG_FOLDER/$VM +} + +# Print guest status +function kvmx_status { + if kvmx_running; then + echo "$BASENAME: $VM guest is running" + PID="`cat $PIDFILE`" + ps $PID + else + echo "$BASENAME: $VM guest is stopped" + fi +} + +# Dispatch +if type kvmx_$ACTION 2> /dev/null | grep -q 'function'; then + kvmx_initialize + kvmx_$ACTION $* fi |