#!/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_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 $name } 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" lxc_container_inside $name lxc_install_lxc_inside $prefix } function lxc_install_lxc_inside() { local prefix="$1" 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 <