|
|
#!/bin/bash
function check_container_missing() { if container_exists "$CONTAINER"; then echoerr "$CONTAINER already created!" exit 1 fi }
function usage() { echo 'USAGE with options:' echo -e "\t\tlxc-miaou-create <CONTAINER_NAME> -o sameuser[,nesting,ssh]" }
function check() { check_container_missing || return 1 return 0 }
function set_options() { declare -a options=("$@") length=${#options[@]} if [[ "$length" -ne 0 ]]; then if [[ "$length" -ne 2 ]]; then echoerr "unrecognized options: $@" && usage && exit 30 else prefix="${options[0]}" option="${options[1]}" if [[ "$prefix" == '-o' ]]; then IFS=',' read -r -a options <<<"$option" for i in ${options[@]}; do case "$i" in sameuser) OPTION_SAMEUSER=true ;; nesting) OPTION_NESTING=true ;; ssh) OPTION_SSH=true ;; *) echoerr "unrecognized options: $@" && usage && exit 32 ;; esac done # echo "OPTION_SAMEUSER=$OPTION_SAMEUSER, OPTION_NESTING=$OPTION_NESTING, OPTION_SSH=$OPTION_SSH" else echoerr "unrecognized options prefix: $prefix" && usage && exit 31 fi fi shift fi }
function create() { local PREFIX="miaou:create"
if [[ "$OPTION_SAMEUSER" == true ]]; then miaou_user=$(whoami) fi
echo -n "creating new container <$CONTAINER> based on image <$CONTAINER_RELEASE>... " bridge_gw=$(lxc network get lxdbr0 ipv4.address | cut -d'/' -f1) packages=(git file bc bash-completion) [[ "$OPTION_SSH" == true ]] && packages+=(openssh-server) packages_string=$(join ', ' "${packages[@]}")
timezone='Indian/Reunion' #FIXME: should be retrieved from host debian_repo='debian.mithril.re' #FIXME: should be retrieved from host
user_data="$( cat <<EOF #cloud-config timezone: '$timezone' apt: preserve_sources_list: false conf: | Acquire::Retries "60"; DPkg::Lock::Timeout "60"; primary: - arches: [default] uri: http://$debian_repo/debian security: - arches: [default] uri: http://$debian_repo/debian-security sources_list: | # generated by miaou deb \$PRIMARY \$RELEASE main deb \$PRIMARY \$RELEASE-updates main deb \$SECURITY \$RELEASE-security main package_update: true package_upgrade: true package_reboot_if_required: true packages: [ $packages_string ] write_files: - path: /etc/sudoers.d/10-add_TOOLBOX_to_secure_path content: > Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/TOOLBOX" runcmd: - [ systemctl, mask, systemd-hostnamed.service ] - [ systemctl, disable, e2scrub_reap.service ] - [ systemctl, disable, systemd-resolved.service, --now ] - [ systemctl, reset-failed ] - [ rm, /etc/resolv.conf] - [ rm, /etc/sudoers.d/90-cloud-init-users] - "echo nameserver $bridge_gw > /etc/resolv.conf" final_message: "Container from datasource \$datasource is finally up, after \$UPTIME seconds" EOF )"
lxc init local:debian/$CONTAINER_RELEASE/cloud "$CONTAINER" --config user.user-data="$user_data" -q
# allow directory `SHARED` to be read-write mounted lxc config set "$CONTAINER" raw.idmap "both $(id -u) 0" -q mkdir -p "$HOME/LXD/SHARED/$CONTAINER"
lxc config device add "$CONTAINER" SHARED disk source="$HOME/LXD/SHARED/$CONTAINER" path=/mnt/SHARED -q lxc config device add "$CONTAINER" TOOLBOX disk source=/TOOLBOX path=/TOOLBOX readonly=true -q lxc config device add "$CONTAINER" MIAOU_BASH disk source=$(realpath /opt/miaou-bash) path=/opt/miaou-bash readonly=true -q
# environment variables lxc config set "$CONTAINER" environment.PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/miaou-bash/tools:/TOOLBOX -q lxc config set "$CONTAINER" environment.container lxc -q
if [[ "$OPTION_NESTING" == true ]]; then lxc config set "$CONTAINER" security.nesting true -q lxc config device add "$CONTAINER" miaou disk source=/opt/miaou path=/opt/miaou readonly=true -q fi
lxc start "$CONTAINER" -q
# initializing miaou-bash lxc exec "$CONTAINER" -- /opt/miaou-bash/init.sh
# default configuration files (btm,) lxc exec "$CONTAINER" -- mkdir -p /root/.config/bottom lxc file push "$MIAOU_BASEDIR/templates/bottom/bottom.toml" "$CONTAINER/root/.config/bottom/bottom.toml" -q
# purge cloud-init after success attempt=0 max_attempt=10 delay=0.2 while ! lxc exec "$CONTAINER" -- bash -c 'systemd-run -q -p After=cloud-final.service -p Type=oneshot --no-block bash -c "\ cloud-init status --wait &&\ cp /var/lib/cloud/data/status.json /root/cloud-status.json &&\ systemctl stop cloud-{config,final,init-local,init}.service &&\ systemctl disable cloud-{config,final,init-local,init}.service &&\ systemctl stop cloud-config.target cloud-init.target &&\ apt-get purge -y cloud-init &&\ rm -rf /var/lib/cloud && \ userdel -rf debian \ " 2>/dev/null '; do attempt=$((attempt++)) if [[ $attempt -gt $max_attempt ]]; then echoerr "systemd unavailable after $(bc <<<"$max_attempt * $delay") seconds" exit 1 else sleep $delay fi done
if [[ "$OPTION_SAMEUSER" == true ]]; then if ! lxc exec "$CONTAINER" -- grep "$miaou_user" /etc/passwd; then lxc exec "$CONTAINER" -- useradd -ms /bin/bash -G sudo "$miaou_user" fi if ! lxc exec "$CONTAINER" -- passwd -S "$miaou_user" | cut -d ' ' -f2 | grep -q ^P; then shadow_passwd=$(load_yaml_from_expanded credential.shadow) shadow_remainder=$(lxc exec "$CONTAINER" -- bash -c "grep $miaou_user /etc/shadow | cut -d':' -f3-") lxc exec "$CONTAINER" -- /opt/miaou-bash/tools/append_or_replace "^$miaou_user:.*:" "$miaou_user:$shadow_passwd:$shadow_remainder" /etc/shadow >/dev/null fi fi
if [[ "$OPTION_SSH" == true && "$OPTION_SAMEUSER" == true ]]; then #FIXME: can be fatser due to openssh-server already installed from cloud-init lxc-miaou-enable-ssh "$CONTAINER" >/dev/null fi
PREFIX="" echoinfo OK
echo "hint: \`lxc login $CONTAINER [--env user=<USER>]\`" [[ "$OPTION_SAMEUSER" == true ]] && echo "hint: \`lxc sameuser $CONTAINER\`"
true }
## MAIN . "$MIAOU_BASEDIR/lib/init.sh" OPTION_SAMEUSER=false OPTION_NESTING=false OPTION_SSH=false PREFIX="miaou"
arg1_required "$@" || (usage && exit 1) readonly CONTAINER=$1 readonly CONTAINER_RELEASE="bookworm"
shift set_options "$@" readonly FULL_OPTIONS="$@"
check create
|