diff --git a/pkg/runner/lxc-helpers-lib.sh b/pkg/runner/lxc-helpers-lib.sh new file mode 100755 index 0000000..81b368b --- /dev/null +++ b/pkg/runner/lxc-helpers-lib.sh @@ -0,0 +1,434 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT + +export DEBIAN_FRONTEND=noninteractive + +LXC_SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +LXC_BIN=/usr/local/bin +LXC_CONTAINER_CONFIG_ALL="unprivileged lxc libvirt docker k8s" +LXC_CONTAINER_CONFIG_DEFAULT="lxc libvirt docker" +LXC_IPV6_PREFIX_DEFAULT="fc15" +LXC_DOCKER_PREFIX_DEFAULT="172.17" +LXC_IPV6_DOCKER_PREFIX_DEFAULT="fd00:d0ca" + +: ${LXC_SUDO:=} +: ${LXC_CONTAINER_RELEASE:=bookworm} +: ${LXC_CONTAINER_CONFIG:=$LXC_CONTAINER_CONFIG_DEFAULT} +: ${LXC_HOME:=/home} +: ${LXC_VERBOSE:=false} + +source /etc/os-release + +function lxc_release() { + echo $VERSION_CODENAME +} + +function lxc_template_release() { + echo lxc-helpers-$LXC_CONTAINER_RELEASE +} + +function lxc_root() { + local name="$1" + + echo /var/lib/lxc/$name/rootfs +} + +function lxc_config() { + local name="$1" + + echo /var/lib/lxc/$name/config +} + +function lxc_container_run() { + local name="$1" + shift + + $LXC_SUDO lxc-attach --clear-env --name $name -- "$@" +} + +function lxc_container_run_script_as() { + local name="$1" + local user="$2" + local script="$3" + + $LXC_SUDO chmod +x $(lxc_root $name)$script + $LXC_SUDO lxc-attach --name $name -- sudo --user $user $script +} + +function lxc_container_run_script() { + local name="$1" + local script="$2" + + $LXC_SUDO chmod +x $(lxc_root $name)$script + lxc_container_run $name $script +} + +function lxc_container_inside() { + local name="$1" + shift + + lxc_container_run $name $LXC_BIN/lxc-helpers.sh "$@" +} + +function lxc_container_user_install() { + local name="$1" + local user_id="$2" + local user="$3" + + if test "$user" = root ; then + return + fi + + local root=$(lxc_root $name) + + if ! $LXC_SUDO grep --quiet "^$user " $root/etc/sudoers ; then + $LXC_SUDO tee $root/usr/local/bin/lxc-helpers-create-user.sh > /dev/null <> /etc/sudoers +sudo --user $user ssh-keygen -b 2048 -N '' -f $LXC_HOME/$user/.ssh/id_rsa +EOF + lxc_container_run_script $name /usr/local/bin/lxc-helpers-create-user.sh + fi +} + +function lxc_maybe_sudo() { + if test $(id -u) != 0 ; then + LXC_SUDO=sudo + fi +} + +function lxc_prepare_environment() { + lxc_maybe_sudo + if ! $(which lxc-create > /dev/null) ; then + $LXC_SUDO apt-get install -y -qq make git libvirt0 libpam-cgfs bridge-utils uidmap dnsmasq-base dnsmasq dnsmasq-utils qemu-user-static + fi +} + +function lxc_container_config_nesting() { + echo 'security.nesting = true' +} + +function lxc_container_config_cap() { + echo 'lxc.cap.drop =' +} + +function lxc_container_config_net() { + cat < /dev/null <<'EOF' +#!/bin/sh -e +for d in $(seq 60); do + getent hosts wikipedia.org > /dev/null && break + sleep 1 +done +getent hosts wikipedia.org > /dev/null || getent hosts wikipedia.org +EOF + $LXC_SUDO chmod +x $wait_networking +} + +function lxc_container_create() { + local name="$1" + + lxc_prepare_environment + lxc_build_template $(lxc_template_release) "$name" +} + +function lxc_container_mount() { + local name="$1" + local dir="$2" + + local config=$(lxc_config $name) + + if ! $LXC_SUDO grep --quiet "lxc.mount.entry = $dir" $config ; then + local relative_dir=${dir##/} + $LXC_SUDO tee -a $config > /dev/null <<< "lxc.mount.entry = $dir $relative_dir none bind,create=dir 0 0" + fi +} + + +function lxc_container_start() { + local name="$1" + + if lxc_running $name ; then + return + fi + + local logs + if $LXC_VERBOSE; then + logs="--logfile=/dev/tty" + fi + + $LXC_SUDO lxc-start $logs $name + $LXC_SUDO lxc-wait --name $name --state RUNNING + lxc_container_run $name /usr/local/bin/lxc-helpers-wait-networking.sh +} + +function lxc_container_stop() { + local name="$1" + + $LXC_SUDO lxc-ls -1 --running --filter="^$name" | while read container ; do + $LXC_SUDO lxc-stop --kill --name="$container" + done +} + +function lxc_container_destroy() { + local name="$1" + local root="$2" + + if lxc_exists "$name" ; then + lxc_container_stop $name $root + $LXC_SUDO lxc-destroy --force --name="$name" + fi +} + +function lxc_exists() { + local name="$1" + + test "$($LXC_SUDO lxc-ls --filter=^$name\$)" +} + +function lxc_running() { + local name="$1" + + test "$($LXC_SUDO lxc-ls --running --filter=^$name\$)" +} + +function lxc_build_template_release() { + local name="$(lxc_template_release)" + + if lxc_exists $name ; then + return + fi + + local root=$(lxc_root $name) + $LXC_SUDO lxc-create --name $name --template debian -- --release=$LXC_CONTAINER_RELEASE + echo 'lxc.apparmor.profile = unconfined' | $LXC_SUDO tee -a $(lxc_config $name) + lxc_container_install_lxc_helpers $name + lxc_container_start $name + lxc_container_run $name apt-get update -qq + lxc_apt_install $name sudo git python3 + lxc_container_stop $name +} + +function lxc_build_template() { + local name="$1" + local newname="$2" + + if lxc_exists $newname ; then + return + fi + + if test "$name" = "$(lxc_template_release)" ; then + lxc_build_template_release + fi + + if ! $LXC_SUDO lxc-copy --name=$name --newname=$newname ; then + echo lxc-copy --name=$name --newname=$newname failed + return 1 + fi + lxc_container_configure $newname +} + +function lxc_apt_install() { + local name="$1" + shift + + lxc_container_inside $name lxc_apt_install_inside "$@" +} + +function lxc_apt_install_inside() { + apt-get install -y -qq "$@" +} + +function lxc_install_lxc() { + local name="$1" + local prefix="$2" + local prefixv6="$3" + + lxc_container_inside $name lxc_install_lxc_inside $prefix $prefixv6 +} + +function lxc_install_lxc_inside() { + local prefix="$1" + local prefixv6="${2:-$LXC_IPV6_PREFIX_DEFAULT}" + + local packages="make git libvirt0 libpam-cgfs bridge-utils uidmap dnsmasq-base dnsmasq dnsmasq-utils qemu-user-static lxc-templates debootstrap" + if test "$(lxc_release)" = bookworm ; then + packages="$packages distro-info" + fi + + lxc_apt_install_inside $packages + + if ! grep --quiet LXC_ADDR=.$prefix.1. /etc/default/lxc-net ; then + systemctl disable --now dnsmasq + apt-get install -y -qq lxc + systemctl stop lxc-net + sed -i -e '/ConditionVirtualization/d' /usr/lib/systemd/system/lxc-net.service + systemctl daemon-reload + cat >> /etc/default/lxc-net < /etc/docker/daemon.json <