provisioning tool for building opinionated architecture
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

409 lines
12 KiB

#!/bin/bash
MIAOU_BASEDIR=$(readlink -f "$(dirname "$0")/..")
# shellcheck source=/dev/null
. "$MIAOU_BASEDIR/lib/functions.sh"
readonly MIAOU_BASEDIR
miaou_init
EXPANDED_CONF="$MIAOU_CONFIGDIR/miaou.expanded.yaml"
NEW_GROUP=lxd
readonly NEW_GROUP EXPANDED_CONF
on_exit() {
if [[ "$SESSION_RELOAD_REQUIRED" == true ]]; then
echo "======================================================"
echo "Session Reload is required (due to new group <$NEW_GROUP>)"
echo "======================================================"
fi
if [ -n "${1:-}" ]; then
echo "Aborted by $1"
elif [ "${status:-}" -ne 0 ]; then
echo "Failure (status $status)"
fi
}
function prepare_lxd {
local PREFIX="lxd:prepare"
# test group lxd assign to current user
if ! groups | grep -q lxd; then
echo "define lxd and assign to user <$USER>"
sudo groupadd --force "$NEW_GROUP"
sudo usermod --append --groups "$NEW_GROUP" "$(whoami)"
exec sg "$NEW_GROUP" "exec '$0' $(printf "'%s' " SESSION_RELOAD_REQUIRED "$@")"
# no further processing because exec has been called!
else
echo "user <$USER> already belongs to group <lxd>!"
fi
sudo /opt/debian-bash/tools/idem_apt_install lxd btrfs-progs
# test lxdbr0
if ! lxc network info lxdbr0 &>/dev/null; then
echo "bridge <lxdbr0> down, so initialization will use default preseed..."
sudo lxd init
# cat <<EOF | sudo lxd init --preseed
# NEW
# networks:
# - config:
# ipv4.address: auto
# ipv6.address: none
# description: ""
# name: lxdbr0
# type: ""
# project: default
# storage_pools:
# - config:
# source: /dev/sda4
# description: ""
# name: default
# driver: btrfs
# profiles:
# - config: {}
# description: ""
# devices:
# eth0:
# name: eth0
# network: lxdbr0
# type: nic
# root:
# path: /
# pool: default
# type: disk
# name: default
# projects: []
# cluster: null
# OLD
# networks:
# - config:
# ipv4.address: auto
# ipv6.address: none
# description: ""
# name: lxdbr0
# type: ""
# project: default
# storage_pools:
# - config:
# source: /dev/sda4
# description: ""
# name: default
# driver: btrfs
# profiles:
# - config: {}
# description: ""
# devices:
# eth0:
# name: eth0
# network: lxdbr0
# type: nic
# root:
# path: /
# pool: default
# type: disk
# name: default
# projects: []
# cluster: null
echo OK
else
echo "bridge <lxdbr0> found implies it has been already initialized!"
fi
set_alias 'sameuser' "exec @ARG1@ -- su --whitelist-environment container_hostname - $(whoami)"
set_alias 'login' 'exec @ARGS@ --mode interactive -- /bin/bash -c $@${user:-root} - exec su --whitelist-environment container_hostname - '
set_alias 'll' 'list -c ns4mDN'
# test environment container hostname
local env_container_hostname=$(lxc profile get default environment.container_hostname)
if [[ -z "$env_container_hostname" ]]; then
env_container_hostname=$(hostname -s)
if env | grep -q container_hostname; then
local previous_container_hostname=$(env | grep container_hostname | cut -d '=' -f2)
env_container_hostname="$previous_container_hostname $env_container_hostname"
fi
echo -n "set environment container_hostname to <$env_container_hostname> ... "
lxc profile set default environment.container_hostname "$env_container_hostname"
PREFIX="" echoinfo OK
else
echo "environment container_hostname <$env_container_hostname> already defined!"
fi
if ! grep -q "root:$(id -u):1" /etc/subuid; then
echo -n "subuid, subgid allowing <$(whoami)> ..."
printf "root:$(id -u):1\n" | sudo tee -a /etc/subuid /etc/subgid
PREFIX="" echoinfo DONE
# root:1000:1
# root:100000:65536
# _lxd:100000:65536
# <USER>:100000:65536
else
echo "subuid, subgid allowing <$(whoami)> already done!"
fi
if [[ ! -d "$HOME/LXD/SHARED" ]]; then
echo -n "$HOME/LXD/SHARED creating ... "
mkdir "$HOME/LXD/SHARED" -p
PREFIX="" echoinfo DONE
else
echo "folder <$HOME/LXD/SHARED> already created!"
fi
if [[ ! -d "$HOME/LXD/BACKUP" ]]; then
echo -n "$HOME/LXD/SHARED creating ... "
mkdir "$HOME/LXD/SHARED" -p
PREFIX="" echoinfo DONE
else
echo "folder <$HOME/LXD/BACKUP> already created!"
fi
}
function set_alias {
local name="$1"
local command="$2"
if ! lxc alias list -f csv | grep -q "^$name,"; then
echo -n "define lxc alias $name ..."
lxc alias add "$name" "$command"
PREFIX="" echoinfo OK
else
echo "lxc alias "$name" already defined!"
fi
}
function miaou_evalfrombashrc() {
local PREFIX="miaou:bashrc"
output=$(
/opt/debian-bash/tools/append_or_replace \
"^eval \"\\$\($MIAOU_BASEDIR/lib/install.sh shellenv\)\"$" \
"eval \"\$($MIAOU_BASEDIR/lib/install.sh shellenv)\"" \
"$HOME/.bashrc"
)
if [[ "$output" == "appended" ]]; then
echo "new path <$MIAOU_BASEDIR> created!"
SESSION_RELOAD_REQUIRED=true
else
echo "path <$MIAOU_BASEDIR> already loaded!"
fi
}
function ask_target() {
PS3='Choose miaou target purpose: '
foods=("Dev" "Beta" "Prod")
select ans in "${foods[@]}"; do
builtin echo "${ans^^}"
break
done
}
function check_credential {
local PREFIX="check:credential"
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.username' &&
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.shadow' &&
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.email' &&
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.password'
}
function check_target() {
case "${TARGET^^}" in
DEV) ;;
BETA) ;;
PROD) ;;
*)
if [[ -f /etc/miaou/defaults.yaml ]]; then
# load already defined target in expanded conf
TARGET=$(grep -Es "^target:" /etc/miaou/defaults.yaml | cut -d ' ' -f2)
else
TARGET=$(ask_target)
fi
;;
esac
TARGET=${TARGET,,} # downcase
return 0
}
function miaou_configfiles() {
local PREFIX="miaou:config"
if [[ ! -d /etc/miaou ]]; then
echo -n "configuration initializing ..."
sudo mkdir -p /etc/miaou
sudo chown "$USER" /etc/miaou
PREFIX="" echoinfo OK
fi
if [[ ! -f /etc/miaou/defaults.yaml ]]; then
echo -n "building /etc/miaou/defaults.yaml for the first time..."
shadow_passwd=$(sudo grep "$CURRENT_USER" /etc/shadow | cut -d ':' -f2)
env current_user="$CURRENT_USER" shadow_passwd="$shadow_passwd" tera -e --env-key env --env-only -t "$MIAOU_BASEDIR/templates/etc/defaults.yaml.j2" -o /etc/miaou/defaults.yaml >/dev/null
yq ".target=\"$TARGET\"" /etc/miaou/defaults.yaml -i
PREFIX="" echoinfo OK
fi
if [[ ! -f /etc/miaou/miaou.yaml ]]; then
echo -n "building /etc/miaou/miaou.yaml for the first time..."
cp "$MIAOU_BASEDIR/templates/etc/miaou.yaml.j2" /etc/miaou/miaou.yaml
PREFIX="" echoinfo OK
fi
PREVIOUS_TARGET=""
echo "expanded configuration stored in <$MIAOU_CONFIGDIR>!"
[[ -f "$EXPANDED_CONF" ]] && PREVIOUS_TARGET=$(grep -Es "^target:" "$EXPANDED_CONF" | cut -d ' ' -f2)
if [[ "$PREVIOUS_TARGET" != "$TARGET" ]]; then
if [[ -z "$PREVIOUS_TARGET" ]]; then
echo "new target defined <$TARGET>"
else
echowarnn "TARGET has changed from <$PREVIOUS_TARGET> to <$TARGET>, do you agree?"
if askConfirmation N; then
echowarn "removing previous settings, please restart <miaou> to apply changes"
rm "$MIAOU_CONFIGDIR" -rf
else
echoerr "TARGET not accepted, exit"
exit 102
fi
fi
yq ".target=\"$TARGET\"" /etc/miaou/defaults.yaml -i
else
echo "target <$TARGET> already defined!"
fi
}
function opt_link() {
if [[ $MIAOU_BASEDIR != '/opt/miaou' ]]; then
if [[ -L '/opt/miaou' && -d '/opt/miaou' && $(readlink /opt/miaou) == "$MIAOU_BASEDIR" ]]; then
echo "symbolic link /opt/miaou already set up!"
else
sudo rm -f /opt/miaou
sudo ln -s "$MIAOU_BASEDIR" /opt/miaou
echo "symbolic link /opt/miaou successfully defined!"
fi
else
echo "real path /opt/miaou already set up!"
fi
}
function miaou_resolver() {
local PREFIX="miaou:resolver"
bridge=$(ip addr show lxdbr0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)
gateway=$(ip route | grep default | cut -d' ' -f3)
if command -v nmcli &>/dev/null; then
if [[ ! -f /etc/NetworkManager/dispatcher.d/50-miaou-resolver ]]; then
echo -n "use NetworkManager dispatcher to deal with LXD bridge automatically..."
sudo cp "$MIAOU_BASEDIR/templates/network-manager/50-miaou-resolver" /etc/NetworkManager/dispatcher.d/
sudo chmod +x /etc/NetworkManager/dispatcher.d/50-miaou-resolver
ACTIVE_CONNECTION=$(nmcli -g NAME connection show --active | head -n1)
nmcli connection up "$ACTIVE_CONNECTION" &>/dev/null
PREFIX="" echoinfo OK
else
echo "miaou-resolver in NetworkManager dispatcher already initialized!"
fi
else
if ! grep -q "nameserver $bridge" /etc/resolv.conf; then
echo "customize resolv.conf from scratch (SERVER)..."
sudo tee /etc/resolv.conf &>/dev/null <<EOF
nameserver $bridge
nameserver $gateway
EOF
PREFIX="" echoinfo OK
else
echo "customize resolv.conf already already defined!"
fi
fi
}
function extra_dev_desktop {
# detect if DEV
# detect if DESKTOP
:
}
function override_lxd_service_to_reload_nftables {
local PREFIX="lxd:override"
if [[ ! -d /etc/systemd/system/lxd.service.d ]]; then
echo -n "override lxd service..."
sudo mkdir -p /etc/systemd/system/lxd.service.d
cat <<EOF | sudo tee /etc/systemd/system/lxd.service.d/override.conf
[Service]
ExecStartPost=systemctl reload nftables.service
EOF
sudo systemctl daemon-reload
PREFIX="" echo "OK"
else
echo "lxd service already overridden!"
fi
}
function ask_for_credential {
local PREFIX="ask:credential"
if ! check_credential 2>/dev/null; then
echo "further details required, please replace any <TO BE DEFINED> by a proper value ...press any key to open editor"
read -rn1
editor /etc/miaou/defaults.yaml
fi
check_credential
echo "successfully checked!"
}
### MAIN
if [[ "${1:-}" == "SESSION_RELOAD_REQUIRED" ]]; then
SESSION_RELOAD_REQUIRED=true
shift
else
SESSION_RELOAD_REQUIRED=false
fi
if [[ "${1:-}" == "shellenv" ]]; then
unset PREFIX
echo "export MIAOU_BASEDIR=$MIAOU_BASEDIR"
echo "export PATH=\"\$MIAOU_BASEDIR/scripts\":\$PATH"
else
. "$MIAOU_BASEDIR/lib/init.sh"
trap 'status=$?; on_exit; exit $status' EXIT
trap 'trap - HUP; on_exit SIGHUP; kill -HUP $$' HUP
trap 'trap - INT; on_exit SIGINT; kill -INT $$' INT
trap 'trap - TERM; on_exit SIGTERM; kill -TERM $$' TERM
PREFIX="miaou"
: $PREFIX
TARGET=${1:-}
CURRENT_USER=$(id -un)
check_target
sudo_required
install_debian_bash
install_mandatory_commands
prepare_toolbox
add_toolbox_sudoers
prepare_nftables
prepare_lxd "$@"
override_lxd_service_to_reload_nftables
miaou_resolver
miaou_evalfrombashrc
miaou_configfiles
ask_for_credential
prepare_nftables
opt_link
extra_dev_desktop
if [[ "$SESSION_RELOAD_REQUIRED" == false ]]; then
echoinfo "successful installation"
else
echowarn "please reload your session, .bashrc needs to be reloaded!"
fi
fi