aboutsummaryrefslogtreecommitdiff
path: root/kvm-manager
blob: 793636a61f2f85d77f0999e4f5859f369ed376dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/bash

set -e

# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
# Date: 2011-01-26
# License: GPL v3+

## expect to pull these values from the environment:
# VMNAME=snapper
# OWNER=jrollins
# RAM=512
# HDA..HDZ=/path/to/disk # optional

if [ -z "$VMNAME" ] ; then
    exit 1
fi

TAP="${TAP:-${VMNAME}0}"
# MAC address is derived from a hash of the host's name and the guest's name:
MAC="${MAC:-$(printf "02:%s" "$(printf "%s\0%s" "$(hostname)" "${VMNAME}" | sha256sum | sed 's/\(..\)/\1:/g' | cut -f1-5 -d:)" )}"
BRIDGE="${BRIDGE:-br0}"

###################
OWNERGROUP=$(groups "$OWNER" | cut -f1 -d\  )
OWNERHOME=$(getent passwd "$OWNER" | cut -f6 -d: )

up() {
# bring up the network tap:
    modprobe -v tun
    ip tuntap add dev "$TAP" mode tap user "$OWNER"
    ip link set "$TAP" up
    brctl addif "$BRIDGE" "$TAP"
    
    chpst -u "$OWNER:$OWNERGROUP" mkdir -p "$OWNERHOME/vms/$VMNAME"

    CDISO="$OWNERHOME/vms/$VMNAME/cd.iso"
    NETBOOT="$OWNERHOME/vms/$VMNAME/netboot"
    KERNEL="$OWNERHOME/vms/$VMNAME/kernel"
    INITRD="$OWNERHOME/vms/$VMNAME/initrd"
    KVMARGS=
    unset KERNEL_CMDLINE
    
    BOOTCHOICE=c

    if [ -e "$KERNEL" -a -e "$INITRD" ] ; then
	KVMARGS="-kernel $KERNEL -initrd $INITRD"
        if [ "$CMDLINE" ]; then
            KERNEL_CMDLINE="$CMDLINE"
        fi
    elif [ -e "$NETBOOT" ] ; then
	BOOTCHOICE=n
    elif [ -e "$CDISO" ] && [ -e $(readlink -f "$CDISO") ] ; then
	KVMARGS="-cdrom $CDISO"
        BOOTCHOICE=d
    fi

    for disk in HD{A..Z}; do
        if printf "%s" "${!disk}" | grep '^/dev/mapper/'; then
            mappername=$(printf "%s" "${!disk}" | sed 's!^/dev/mapper/!!')
            udevadm trigger --subsystem-match=block --attr-match=dm/name="$mappername"
        fi
    done
    udevadm trigger --sysname-match=kvm

    # older versions need to have at least the first disk marked as boot=on or they cannot boot.
    if kvm --version 2>/dev/null | sed 's/.*version \([0-9.]*\).*/\1/' | grep -q '^0' ; then
        first_disk_extra_args=",boot=on"
    else
        first_disk_extra_args=
    fi

    index=0
    # set up the disks, if needed:
    [ -z "$HDA" ] || KVMARGS="$KVMARGS -drive file=$HDA,if=virtio,cache=none,index=$index,format=raw$first_disk_extra_args"
    # loop here on everything after HDA:
    for disk in HD{B..Z}; do
	index=$(( $index + 1 ))
	[ \! -b "${!disk}" ] || KVMARGS="$KVMARGS -drive file=${!disk},if=virtio,cache=none,index=$index,format=raw"
    done

    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
    
    MONITORNAME="$OWNERHOME/vms/$VMNAME/monitor.socket"
    CONSOLENAME="$OWNERHOME/vms/$VMNAME/console.socket"

    kvmsend() {
        socat STDIO "UNIX:$MONITORNAME" <<EOF
$1
EOF
    }

    chpst -u "$OWNER:$OWNERGROUP:kvm" \
        /usr/bin/kvm $KVMARGS \
        -M "${MACHINE:-pc}" \
	${KERNEL_CMDLINE:+-append "$KERNEL_CMDLINE"} \
        -enable-kvm \
        -nodefaults \
        -nographic \
        -name "$VMNAME" \
        -m "$RAM" \
        -boot "$BOOTCHOICE" \
        -chardev "socket,id=monitor,path=$MONITORNAME,server,nowait" -mon chardev=monitor,mode=readline \
        -rtc base=utc \
        -usb \
        -device virtio-balloon-pci,id=balloon0,bus=pci.0 \
        -chardev "socket,id=serial0,path=$CONSOLENAME,server" -device isa-serial,chardev=serial0 \
        -smp "${SMP:-1},maxcpus=${MAXCPUS:-8}" \
        -device "virtio-net-pci,vlan=0,id=net0,mac=$MAC,bus=pci.0" \
        -net "tap,ifname=$TAP,script=no,downscript=no,vlan=0,name=hostnet0" &

    chpst -u "$OWNER:$OWNERGROUP" \
        /usr/bin/screen -D -m -L -c /etc/screenrc.kvm-manager -S "$VMNAME" -t "$VMNAME" socat STDIO,raw,echo=0 "UNIX:${CONSOLENAME},retry=30" &

    set +e
    # handle regular signals
    trap 'kvmsend system_reset; wait %1' HUP
    trap 'kvmsend system_powerdown; wait %1' TERM
    trap 'kvmsend cont; wait %1' CONT
    trap 'kill -s TERM %1' QUIT
 # use SIGINT instead of SIGSTOP for freezing the guest because
 # trapping SIGSTOP is undefined:
 # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_28
    trap 'kvmsend stop; wait %1' INT
    trap 'kill %1 ; kill %2' EXIT

    wait %1
}


down() {
    brctl delif "$BRIDGE" "$TAP"
    ip link set "$TAP" down
    ip tuntap del mode tap dev "$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]" >&2
	exit 1
	;;
esac