summaryrefslogtreecommitdiff
path: root/start-container-qemu.sh
blob: 4521e6c4b2240265f4c1a870b241303937ba3e8d (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
#!/bin/bash

set -ef -o pipefail

# Save stdout/stderr file descriptors
exec 3>&1 4>&2

# Make sure all output goes to stderr
exec 1>&2

docker_args=()

initrd_url=""
kernel_url=""
prefix=""
task="build"
weight="1"

while [ $# -gt 0 ]; do
    case "$1" in
	--initrd_url) initrd_url="$2" ;;
	--kernel_url) kernel_url="$2" ;;
	--prefix) prefix="$2"; docker_args=("${docker_args[@]}" "$1" "$2") ;;
	--task) task="$2"; docker_args=("${docker_args[@]}" "$1" "$2") ;;
	--weight) weight="$2"; docker_args=("${docker_args[@]}" "$1" "$2") ;;
	*) docker_args=("${docker_args[@]}" "$1" "$2")
    esac
    shift 2
done

container=$(mktemp)

# Run container as privileged to mount host's /dev inside container to gain
# access to /dev/kvm.
# Publish container's port 2222, which is forwarded to VM's ssh server.
$(dirname "$0")/start-container-docker.sh "${docker_args[@]}" --docker_opts "--privileged --publish 2222" > "$container"

trap "rm $container; cleanup_all_containers" EXIT

. "$container"

eval "host=\$${prefix}container_host"
eval "port=\$${prefix}container_port"
eval "container_id=\$${prefix}container_id"
container_exec ()
{
    remote_exec "$host:$port:/" "$@"
}

# FIXME: install qemu-system-arm into docker images.
container_exec sudo apt-get update
container_exec sudo apt-get install -y qemu-system-arm nfs-kernel-server

# /tmp is a scratch volume outside of / filesystem.
nfsroot="/tmp/nfsroot"
container_exec sudo mkdir "$nfsroot"
container_exec sudo rsync -a --one-file-system / $nfsroot/

nfsip=$(docker -H $host:2375 inspect --format {{.NetworkSettings.IPAddress}} "$container_id")

# Start NFS server inside container.
# Note, for NFS server to work inside container kernel should have
# NFS module loaded, which seems easiest achieved by installing "nfs-kernel-server"
# package on the host.
bind_mounts=($(print_bind_mounts "$task"))
echo "$nfsroot *(rw,async,no_root_squash,no_subtree_check,insecure)" | container_exec sudo tee -a /etc/exports
for bind_mount in "${bind_mounts[@]}"; do
    dir="$(echo $bind_mount | cut -s -d: -f 2)"
    rw="$(echo $bind_mount | cut -s -d: -f 3)"
    rw="${rw:-rw}"
    mkdir -p "$nfsroot/$dir"

    echo "$dir *($rw,async,no_root_squash,no_subtree_check,insecure)" | container_exec sudo tee -a /etc/exports
    echo "$nfsip:$dir $dir nfs defaults,$rw,vers=3,proto=udp 0 0" | container_exec sudo tee -a "$nfsroot/etc/fstab"
done
container_exec sudo /etc/init.d/rpcbind start
container_exec sudo /etc/init.d/nfs-kernel-server start

# Add tcwg-buildslave to "kvm" group to avoid running QEMU as root
container_exec sudo addgroup $USER kvm

# CPU is limited (on contention) by docker container.
ncpus=$(container_exec nproc --all)
memory=$(print_memory_limit "$task" "$weight")
# Reduce memory limit for VM to leave something for QEMU itself.
memory=$(($memory*2/3))

wget_wildcard_url "$kernel_url"
rsync -e "ssh -p$port" -az "$(ls $(basename "$kernel_url"))" "$host:/tmp/kernel"
wget_wildcard_url "$initrd_url"
rsync -e "ssh -p$port" -az "$(ls $(basename "$initrd_url"))" "$host:/tmp/initrd"

# "-f" is to start qemu in the background.
# "-Snone" is to avoid mixing this session with any other shared sessions.
remote_exec "$host:$port:/:-f -Snone" \
	    qemu-system-aarch64 -machine virt -enable-kvm -cpu host \
	    -smp $ncpus -m $memory -nographic -monitor none \
	    -kernel /tmp/kernel -initrd /tmp/initrd \
	    -append "root=/dev/nfs nfsroot=$nfsip:$nfsroot,udp rw ip=dhcp" \
	    -netdev user,id=unet,hostfwd=tcp::2222-:22 \
	    -device virtio-net-device,netdev=unet \
	    -s > ${prefix}qemu.log 2>&1

qemu_port=$(docker -H $host:2375 port $container_id 2222 | cut -d: -f 2)

ret=0
wait_for_ssh_server $host $qemu_port || ret=$?
if [ x"$ret" != x"0" ]; then
    echo "SSH server did not respond, exiting"
    exit 1
fi

# Do not remove the container upon exit: it is now ready
trap EXIT

# Restore stdout/stderr
exec 1>&3 2>&4

cat "$container"
cat <<EOF
${prefix}container_port=$qemu_port
${prefix}container_exec ()
{
  remote_exec "$host:$qemu_port:\$(pwd)" "\$@"
}
EOF
rm "$container"