1
1
mirror of https://gitlab.archlinux.org/archlinux/infrastructure.git synced 2025-01-18 08:06:16 +01:00
infrastructure/roles/gitlab_runner/files/libvirt-executor
Kristian Klausen f756d51f94
gitlab_runner: Boot VMs in UEFI mode
There is no technical reason for this at the moment, but UEFI is the de
facto firmware for x86-64, so let's be modern.
2024-12-15 15:32:02 +01:00

109 lines
3.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -o nounset -o errexit -o pipefail
readonly libvirt_pool="images"
ssh() {
command ssh \
-i "/run/libvirt-executor/id_ed25519_$(vm_name)" \
-F /dev/null \
-o ServerAliveCountMax=2 \
-o ServerAliveInterval=15 \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=off \
-o LogLevel=error \
"root@${1}" "${@:2}"
}
vm_name() {
printf 'runner-%s-project-%d-pipeline-%d-job-%d\n' "${CUSTOM_ENV_CI_RUNNER_SHORT_TOKEN}" "${CUSTOM_ENV_CI_PROJECT_ID}" "${CUSTOM_ENV_CI_PIPELINE_IID}" "${CUSTOM_ENV_CI_JOB_ID}"
}
vm_ip() {
local ip
ip="$(virsh -q domifaddr "${1}" | awk -F'[ /]+' '{print $5}')"
if [[ -n ${ip} ]]; then
echo "${ip}"
return 0
fi
return 1
}
wait_for_ssh() {
for _ in {1..30}; do
if ! ip="$(vm_ip "${1}")"; then
echo "Waiting for network"
sleep 1
continue
fi
if ! ssh "${ip}" true; then
echo "Waiting for SSH to be ready"
sleep 1
continue
fi
return 0
done
echo 'Waited 30 seconds for VM to start, exiting...'
exit "${SYSTEM_FAILURE_EXIT_CODE:-1}"
}
# https://docs.gitlab.com/runner/executors/custom.html#prepare
prepare() {
# shellcheck disable=SC2064
trap "exit ${SYSTEM_FAILURE_EXIT_CODE:-1}" ERR
if [[ ! -f /usr/local/lib/libvirt-executor/backing-vol-name ]]; then
echo 'Backing volume not found...'
exit "${SYSTEM_FAILURE_EXIT_CODE:-1}"
fi
local backing_volume
backing_volume="$(</usr/local/lib/libvirt-executor/backing-vol-name)"
mkdir -p /run/libvirt-executor
chmod 700 /run/libvirt-executor
ssh-keygen -q -N "" -f /run/libvirt-executor/id_ed25519_$(vm_name) -t ed25519
local ssh_authorized_keys_root
ssh_authorized_keys_root="$(base64 -w 0 /run/libvirt-executor/id_ed25519_$(vm_name).pub)"
virsh vol-create-as "${libvirt_pool}" "$(vm_name).qcow2" 0 --format qcow2 --backing-vol "${backing_volume}" --backing-vol-format qcow2
virsh define <(sed -e "s/\$vm_name/$(vm_name)/" -e "s/\$ssh_authorized_keys_root/${ssh_authorized_keys_root}/" /usr/local/lib/libvirt-executor/domain_template.xml)
virsh start "$(vm_name)"
wait_for_ssh "$(vm_name)"
}
# https://docs.gitlab.com/runner/executors/custom.html#run
run() {
local ip
ip="$(vm_ip "$(vm_name)")"
if [[ ${2} == prepare_script ]]; then
# TODO: Get this fixed upstream or perhaps we should just install inetutils?
# https://gitlab.com/gitlab-org/gitlab-runner/-/blob/v17.5.2/shells/bash.go?ref_type=tags#L452-L456
ssh "${ip}" bash < <(sed 's/$(hostname)/$(hostnamectl hostname)/' "${1}") || exit "${BUILD_FAILURE_EXIT_CODE:-1}"
else
ssh "${ip}" bash < "${1}" || exit "${BUILD_FAILURE_EXIT_CODE:-1}"
fi
}
# https://docs.gitlab.com/runner/executors/custom.html#cleanup
cleanup() {
rm /run/libvirt-executor/id_ed25519_$(vm_name){,.pub}
virsh destroy "$(vm_name)" || true
virsh undefine --nvram --remove-all-storage "$(vm_name)"
}
case "${1:-}" in
prepare)
prepare
;;
run)
run "${2}" "${3}"
;;
cleanup)
cleanup
;;
*)
echo "Error invalid command: ${1:-}"
exit 1;
esac