246 lines
4.5 KiB
Bash
Executable File
246 lines
4.5 KiB
Bash
Executable File
#!/bin/sh -eu
|
|
self=$(readlink -f $0)
|
|
self=$(dirname "$self")
|
|
|
|
if [ -f /etc/image-control.conf ]
|
|
then
|
|
. /etc/image-control.conf
|
|
fi
|
|
|
|
base=$1
|
|
cmd=$2
|
|
shift 2
|
|
|
|
if [ ! -d $self/$base ]
|
|
then
|
|
printf "Image '%s' does not exist\n" "$base" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ssh_opts="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
|
guestport=22
|
|
|
|
guest_ssh() {
|
|
ssh $ssh_opts "$@"
|
|
}
|
|
|
|
cpu_opts() {
|
|
if [ "$(uname -m)" = "$1" ] && [ -e /dev/kvm ]
|
|
then
|
|
printf "%s" "-cpu host -enable-kvm"
|
|
return
|
|
fi
|
|
case "$1" in
|
|
aarch64)
|
|
printf "%s" "-M virt -cpu cortex-a53"
|
|
;;
|
|
x86_64)
|
|
printf "%s" "-cpu qemu64"
|
|
;;
|
|
ppc64le)
|
|
printf "%s" "-cpu power9 -machine pseries"
|
|
;;
|
|
*)
|
|
printf "Unsupported architecture '%s'\n" "$arch" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_docker_boot() {
|
|
docker run -d \
|
|
-v "$self/$base":/base:ro \
|
|
--mount type=tmpfs,destination=/var/tmp \
|
|
--device /dev/kvm \
|
|
--cpus=2 \
|
|
-p 127.0.0.1:$port:$port \
|
|
--rm \
|
|
--name "builds_job_${BUILD_JOB_ID:-unknown_$(date +"%s")}" \
|
|
qemu /bin/${qemu:-qemu-system-$arch} \
|
|
-m ${MEMORY:-4096} \
|
|
-smp cpus=2 \
|
|
-net nic,model=virtio -net user,hostfwd=tcp::$port-:$guestport \
|
|
-display none \
|
|
-device virtio-rng-pci \
|
|
-device virtio-balloon \
|
|
-drive file="$wd/$arch/root.img.qcow2",media=disk,snapshot=on,${driveopts:-if=virtio} \
|
|
"$@" > /tmp/docker-$port.id
|
|
}
|
|
|
|
_qemu_boot() {
|
|
${qemu:-qemu-system-$arch} \
|
|
-pidfile /tmp/qemu-$port.id \
|
|
-m ${MEMORY:-4096} \
|
|
-smp cpus=2 \
|
|
-net nic,model=virtio -net user,hostfwd=tcp:127.0.0.1:$port-:$guestport \
|
|
-display none \
|
|
-device virtio-rng-pci \
|
|
-device virtio-balloon \
|
|
-drive file="$wd/$arch/root.img.qcow2",media=disk,snapshot=on,${driveopts:-if=virtio} \
|
|
"$@" &
|
|
}
|
|
|
|
_qemu_chroot_boot() {
|
|
qemu-chroot \
|
|
-p /tmp/qemu-$port.id \
|
|
-b "$self/$base":/base \
|
|
-b /var/tmp:/var/tmp \
|
|
/bin/${qemu:-qemu-system-$arch} \
|
|
-m ${MEMORY:-4096} \
|
|
-smp cpus=2 \
|
|
-net nic,model=virtio -net user,hostfwd=tcp:127.0.0.1:$port-:$guestport \
|
|
-display none \
|
|
-device virtio-rng-pci \
|
|
-device virtio-balloon \
|
|
-drive file="$wd/$arch/root.img.qcow2",media=disk,snapshot=on,${driveopts:-if=virtio} \
|
|
"$@" &
|
|
}
|
|
|
|
_qemu_kvm_boot() {
|
|
qemu-kvm \
|
|
-pidfile /tmp/qemu-$port.id \
|
|
-m ${MEMORY:-4096} \
|
|
-smp cpus=2 \
|
|
-net nic,model=virtio -net user,hostfwd=tcp:127.0.0.1:$port-:$guestport \
|
|
-display none \
|
|
-device virtio-rng-pci \
|
|
-device virtio-balloon \
|
|
-drive file="$wd/$arch/root.img.qcow2",media=disk,snapshot=on,${driveopts:-if=virtio} \
|
|
"$@" &
|
|
}
|
|
|
|
_boot() {
|
|
if [ "$means" = "docker" ]
|
|
then
|
|
_docker_boot "$@"
|
|
elif [ "$means" = "qemu" ]
|
|
then
|
|
_qemu_boot "$@"
|
|
elif [ "$means" = "qemu-chroot" ]
|
|
then
|
|
_qemu_chroot_boot "$@"
|
|
elif [ "$means" = "qemu-kvm" ]
|
|
then
|
|
_qemu_kvm_boot "$@"
|
|
fi
|
|
}
|
|
|
|
cmd_boot() {
|
|
arch=$1
|
|
shift
|
|
|
|
if [ "$arch" = "default" ]
|
|
then
|
|
arch="$default_arch"
|
|
fi
|
|
if [ ! -e "$self/$base/$arch/root.img.qcow2" ]
|
|
then
|
|
printf "Image '%s' is not available for arch '%s'\n" "$base" "$arch" >&2
|
|
exit 1
|
|
fi
|
|
|
|
port=$1
|
|
if [ "$#" -gt 1 ]
|
|
then
|
|
means=$2
|
|
else
|
|
means="${default_means:-docker}"
|
|
fi
|
|
|
|
if [ "$means" = "docker" ]
|
|
then
|
|
wd="/base"
|
|
elif [ "$means" = "qemu" ]
|
|
then
|
|
wd="$self/$base"
|
|
elif [ "$means" = "qemu-chroot" ]
|
|
then
|
|
wd="/base"
|
|
elif [ "$means" = "qemu-kvm" ]
|
|
then
|
|
wd="$self/$base"
|
|
else
|
|
printf "Unknown boot mode '%s'\n" "$means" >&2
|
|
exit 1
|
|
fi
|
|
|
|
boot
|
|
}
|
|
|
|
_wait_boot() {
|
|
port=$1
|
|
attempts=0
|
|
echo "Waiting for VM to come up..."
|
|
while ! guest_ssh -p "$port" build@localhost echo Hello world 2>&1 >/dev/null
|
|
do
|
|
sleep 5
|
|
attempts=$((attempts + 1))
|
|
if [ "$attempts" -eq 20 ]
|
|
then
|
|
echo "Giving up."
|
|
cmd_cleanup "$port"
|
|
exit 1
|
|
fi
|
|
echo "Attempt $attempts..."
|
|
done
|
|
}
|
|
|
|
cmd_cleanup() {
|
|
port=$1
|
|
# Power off
|
|
if [ "$#" -eq 1 ]
|
|
then
|
|
if [ -e /tmp/docker-$port.id ]
|
|
then
|
|
cid=$(cat /tmp/docker-$port.id)
|
|
guest_ssh -p $port build@localhost $poweroff_cmd || true
|
|
sleep 2
|
|
docker kill $cid && sleep 2 || true
|
|
rm /tmp/docker-$port.id
|
|
fi
|
|
if [ -e /tmp/qemu-$port.id ]
|
|
then
|
|
cid=$(cat /tmp/qemu-$port.id)
|
|
guest_ssh -p $port build@localhost $poweroff_cmd || true
|
|
sleep 2
|
|
kill $cid || true
|
|
rm -f /tmp/qemu-$port.id
|
|
fi
|
|
fi
|
|
}
|
|
|
|
if ! [ -e "$self/$base/functions" ]
|
|
then
|
|
printf "Missing base image functions '%s'\n" "$base" >&2
|
|
exit 1
|
|
fi
|
|
|
|
. $self/$base/functions
|
|
|
|
case "$cmd" in
|
|
boot)
|
|
cmd_boot "$@"
|
|
;;
|
|
cleanup)
|
|
cmd_cleanup "$@"
|
|
;;
|
|
sanity-check)
|
|
sanity_check "$@"
|
|
;;
|
|
install)
|
|
install "$@"
|
|
;;
|
|
add-repo)
|
|
add_repository "$@"
|
|
;;
|
|
ssh)
|
|
port=$1
|
|
shift
|
|
guest_ssh -p "$port" build@localhost "$@"
|
|
;;
|
|
*)
|
|
printf "Unknown command '%s'\n" "$cmd" >&2
|
|
exit 1
|
|
;;
|
|
esac
|