aboutsummaryrefslogtreecommitdiff
path: root/kvmx
diff options
context:
space:
mode:
Diffstat (limited to 'kvmx')
-rwxr-xr-xkvmx358
1 files changed, 284 insertions, 74 deletions
diff --git a/kvmx b/kvmx
index 00a41be..75c0c3a 100755
--- a/kvmx
+++ b/kvmx
@@ -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