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

9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
  1. #!/bin/bash
  2. MIAOU_BASEDIR=$(readlink -f "$(dirname "$0")/..")
  3. # shellcheck source=/dev/null
  4. . "$MIAOU_BASEDIR/lib/functions.sh"
  5. readonly MIAOU_BASEDIR
  6. miaou_init
  7. EXPANDED_CONF="$MIAOU_CONFIGDIR/miaou.expanded.yaml"
  8. NEW_GROUP=lxd
  9. readonly NEW_GROUP EXPANDED_CONF
  10. on_exit() {
  11. if [[ "$SESSION_RELOAD_REQUIRED" == true ]]; then
  12. echo "======================================================"
  13. echo "Session Reload is required (due to new group <$NEW_GROUP>)"
  14. echo "======================================================"
  15. fi
  16. if [ -n "${1:-}" ]; then
  17. echo "Aborted by $1"
  18. elif [ "${status:-}" -ne 0 ]; then
  19. echo "Failure (status $status)"
  20. fi
  21. }
  22. function prepare_lxd {
  23. local PREFIX="lxd:prepare"
  24. # test group lxd assign to current user
  25. if ! groups | grep -q lxd; then
  26. echo "define lxd and assign to user <$USER>"
  27. sudo groupadd --force "$NEW_GROUP"
  28. sudo usermod --append --groups "$NEW_GROUP" "$(whoami)"
  29. exec sg "$NEW_GROUP" "exec '$0' $(printf "'%s' " SESSION_RELOAD_REQUIRED "$@")"
  30. # no further processing because exec has been called!
  31. else
  32. echo "user <$USER> already belongs to group <lxd>!"
  33. fi
  34. sudo /opt/miaou-bash/tools/idem_apt_install lxd btrfs-progs
  35. # test lxdbr0
  36. if ! lxc network info lxdbr0 &>/dev/null; then
  37. echo "bridge <lxdbr0> down, so initialization will use default preseed..."
  38. sudo lxd init
  39. # cat <<EOF | sudo lxd init --preseed
  40. # NEW
  41. # networks:
  42. # - config:
  43. # ipv4.address: auto
  44. # ipv6.address: none
  45. # description: ""
  46. # name: lxdbr0
  47. # type: ""
  48. # project: default
  49. # storage_pools:
  50. # - config:
  51. # source: /dev/sda4
  52. # description: ""
  53. # name: default
  54. # driver: btrfs
  55. # profiles:
  56. # - config: {}
  57. # description: ""
  58. # devices:
  59. # eth0:
  60. # name: eth0
  61. # network: lxdbr0
  62. # type: nic
  63. # root:
  64. # path: /
  65. # pool: default
  66. # type: disk
  67. # name: default
  68. # projects: []
  69. # cluster: null
  70. # OLD
  71. # networks:
  72. # - config:
  73. # ipv4.address: auto
  74. # ipv6.address: none
  75. # description: ""
  76. # name: lxdbr0
  77. # type: ""
  78. # project: default
  79. # storage_pools:
  80. # - config:
  81. # source: /dev/sda4
  82. # description: ""
  83. # name: default
  84. # driver: btrfs
  85. # profiles:
  86. # - config: {}
  87. # description: ""
  88. # devices:
  89. # eth0:
  90. # name: eth0
  91. # network: lxdbr0
  92. # type: nic
  93. # root:
  94. # path: /
  95. # pool: default
  96. # type: disk
  97. # name: default
  98. # projects: []
  99. # cluster: null
  100. echo OK
  101. else
  102. echo "bridge <lxdbr0> found implies it has been already initialized!"
  103. fi
  104. set_alias 'sameuser' "exec @ARG1@ -- su --whitelist-environment container_hostname - $(whoami)"
  105. set_alias 'login' 'exec @ARGS@ --mode interactive -- /bin/bash -c $@${user:-root} - exec su --whitelist-environment container_hostname - '
  106. set_alias 'll' 'list -c ns4mDN'
  107. # test environment container hostname
  108. local env_container_hostname=$(lxc profile get default environment.container_hostname)
  109. if [[ -z "$env_container_hostname" ]]; then
  110. env_container_hostname=$(hostname -s)
  111. if env | grep -q container_hostname; then
  112. local previous_container_hostname=$(env | grep container_hostname | cut -d '=' -f2)
  113. env_container_hostname="$previous_container_hostname $env_container_hostname"
  114. fi
  115. echo -n "set environment container_hostname to <$env_container_hostname> ... "
  116. lxc profile set default environment.container_hostname "$env_container_hostname"
  117. PREFIX="" echoinfo OK
  118. else
  119. echo "environment container_hostname <$env_container_hostname> already defined!"
  120. fi
  121. if ! grep -q "root:$(id -u):1" /etc/subuid; then
  122. echo -n "subuid, subgid allowing <$(whoami)> ..."
  123. printf "root:$(id -u):1\n" | sudo tee -a /etc/subuid /etc/subgid
  124. PREFIX="" echoinfo DONE
  125. # root:1000:1
  126. # root:100000:65536
  127. # _lxd:100000:65536
  128. # <USER>:100000:65536
  129. else
  130. echo "subuid, subgid allowing <$(whoami)> already done!"
  131. fi
  132. if [[ ! -d "$HOME/LXD/SHARED" ]]; then
  133. echo -n "$HOME/LXD/SHARED creating ... "
  134. mkdir "$HOME/LXD/SHARED" -p
  135. PREFIX="" echoinfo DONE
  136. else
  137. echo "folder <$HOME/LXD/SHARED> already created!"
  138. fi
  139. if [[ ! -d "$HOME/LXD/BACKUP" ]]; then
  140. echo -n "$HOME/LXD/SHARED creating ... "
  141. mkdir "$HOME/LXD/SHARED" -p
  142. PREFIX="" echoinfo DONE
  143. else
  144. echo "folder <$HOME/LXD/BACKUP> already created!"
  145. fi
  146. }
  147. function set_alias {
  148. local name="$1"
  149. local command="$2"
  150. if ! lxc alias list -f csv | grep -q "^$name,"; then
  151. echo -n "define lxc alias $name ..."
  152. lxc alias add "$name" "$command"
  153. PREFIX="" echoinfo OK
  154. else
  155. echo "lxc alias "$name" already defined!"
  156. fi
  157. }
  158. function miaou_evalfrombashrc() {
  159. local PREFIX="miaou:bashrc"
  160. output=$(
  161. /opt/miaou-bash/tools/append_or_replace \
  162. "^eval \"\\$\($MIAOU_BASEDIR/lib/install.sh shellenv\)\"$" \
  163. "eval \"\$($MIAOU_BASEDIR/lib/install.sh shellenv)\"" \
  164. "$HOME/.bashrc"
  165. )
  166. if [[ "$output" == "appended" ]]; then
  167. echo "new path <$MIAOU_BASEDIR> created!"
  168. SESSION_RELOAD_REQUIRED=true
  169. else
  170. echo "path <$MIAOU_BASEDIR> already loaded!"
  171. fi
  172. }
  173. function ask_target() {
  174. PS3='Choose miaou target purpose: '
  175. foods=("Dev" "Beta" "Prod")
  176. select ans in "${foods[@]}"; do
  177. builtin echo "${ans^^}"
  178. break
  179. done
  180. }
  181. function check_credential {
  182. local PREFIX="check:credential"
  183. check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.username' &&
  184. check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.shadow' &&
  185. check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.email' &&
  186. check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.password'
  187. }
  188. function check_target() {
  189. case "${TARGET^^}" in
  190. DEV) ;;
  191. BETA) ;;
  192. PROD) ;;
  193. *)
  194. if [[ -f /etc/miaou/defaults.yaml ]]; then
  195. # load already defined target in expanded conf
  196. TARGET=$(grep -Es "^target:" /etc/miaou/defaults.yaml | cut -d ' ' -f2)
  197. else
  198. TARGET=$(ask_target)
  199. fi
  200. ;;
  201. esac
  202. TARGET=${TARGET,,} # downcase
  203. return 0
  204. }
  205. function miaou_configfiles() {
  206. local PREFIX="miaou:config"
  207. if [[ ! -d /etc/miaou ]]; then
  208. echo -n "configuration initializing ..."
  209. sudo mkdir -p /etc/miaou
  210. sudo chown "$USER" /etc/miaou
  211. PREFIX="" echoinfo OK
  212. fi
  213. if [[ ! -f /etc/miaou/defaults.yaml ]]; then
  214. echo -n "building /etc/miaou/defaults.yaml for the first time..."
  215. shadow_passwd=$(sudo grep "$CURRENT_USER" /etc/shadow | cut -d ':' -f2)
  216. 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
  217. yq ".target=\"$TARGET\"" /etc/miaou/defaults.yaml -i
  218. PREFIX="" echoinfo OK
  219. fi
  220. if [[ ! -f /etc/miaou/miaou.yaml ]]; then
  221. echo -n "building /etc/miaou/miaou.yaml for the first time..."
  222. cp "$MIAOU_BASEDIR/templates/etc/miaou.yaml.j2" /etc/miaou/miaou.yaml
  223. PREFIX="" echoinfo OK
  224. fi
  225. PREVIOUS_TARGET=""
  226. echo "expanded configuration stored in <$MIAOU_CONFIGDIR>!"
  227. [[ -f "$EXPANDED_CONF" ]] && PREVIOUS_TARGET=$(grep -Es "^target:" "$EXPANDED_CONF" | cut -d ' ' -f2)
  228. if [[ "$PREVIOUS_TARGET" != "$TARGET" ]]; then
  229. if [[ -z "$PREVIOUS_TARGET" ]]; then
  230. echo "new target defined <$TARGET>"
  231. else
  232. echowarnn "TARGET has changed from <$PREVIOUS_TARGET> to <$TARGET>, do you agree?"
  233. if askConfirmation N; then
  234. echowarn "removing previous settings, please restart <miaou> to apply changes"
  235. rm "$MIAOU_CONFIGDIR" -rf
  236. else
  237. echoerr "TARGET not accepted, exit"
  238. exit 102
  239. fi
  240. fi
  241. yq ".target=\"$TARGET\"" /etc/miaou/defaults.yaml -i
  242. else
  243. echo "target <$TARGET> already defined!"
  244. fi
  245. }
  246. function opt_link() {
  247. if [[ $MIAOU_BASEDIR != '/opt/miaou' ]]; then
  248. if [[ -L '/opt/miaou' && -d '/opt/miaou' && $(readlink /opt/miaou) == "$MIAOU_BASEDIR" ]]; then
  249. echo "symbolic link /opt/miaou already set up!"
  250. else
  251. sudo rm -f /opt/miaou
  252. sudo ln -s "$MIAOU_BASEDIR" /opt/miaou
  253. echo "symbolic link /opt/miaou successfully defined!"
  254. fi
  255. else
  256. echo "real path /opt/miaou already set up!"
  257. fi
  258. }
  259. function miaou_resolver() {
  260. local PREFIX="miaou:resolver"
  261. bridge=$(ip addr show lxdbr0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)
  262. gateway=$(ip route | grep default | cut -d' ' -f3)
  263. if command -v nmcli &>/dev/null; then
  264. if [[ ! -f /etc/NetworkManager/dispatcher.d/50-miaou-resolver ]]; then
  265. echo -n "use NetworkManager dispatcher to deal with LXD bridge automatically..."
  266. sudo cp "$MIAOU_BASEDIR/templates/network-manager/50-miaou-resolver" /etc/NetworkManager/dispatcher.d/
  267. sudo chmod +x /etc/NetworkManager/dispatcher.d/50-miaou-resolver
  268. ACTIVE_CONNECTION=$(nmcli -g NAME connection show --active | head -n1)
  269. sudo nmcli connection up "$ACTIVE_CONNECTION" &>/dev/null
  270. PREFIX="" echoinfo OK
  271. else
  272. echo "miaou-resolver in NetworkManager dispatcher already initialized!"
  273. fi
  274. else
  275. if ! grep -q "nameserver $bridge" /etc/resolv.conf; then
  276. echo "customize resolv.conf from scratch (SERVER)..."
  277. sudo tee /etc/resolv.conf &>/dev/null <<EOF
  278. nameserver $bridge
  279. nameserver $gateway
  280. EOF
  281. PREFIX="" echoinfo OK
  282. else
  283. echo "customize resolv.conf already already defined!"
  284. fi
  285. fi
  286. }
  287. function extra_dev_desktop {
  288. # detect if DEV
  289. # detect if DESKTOP
  290. :
  291. }
  292. function override_lxd_service_to_reload_nftables {
  293. local PREFIX="lxd:override"
  294. if [[ ! -d /etc/systemd/system/lxd.service.d ]]; then
  295. echo -n "override lxd service..."
  296. sudo mkdir -p /etc/systemd/system/lxd.service.d
  297. cat <<EOF | sudo tee /etc/systemd/system/lxd.service.d/override.conf
  298. [Service]
  299. ExecStartPost=systemctl reload nftables.service
  300. EOF
  301. sudo systemctl daemon-reload
  302. PREFIX="" echo "OK"
  303. else
  304. echo "lxd service already overridden!"
  305. fi
  306. }
  307. function ask_for_credential {
  308. local PREFIX="ask:credential"
  309. if ! check_credential 2>/dev/null; then
  310. echo "further details required, please replace any <TO BE DEFINED> by a proper value ...press any key to open editor"
  311. read -rn1
  312. editor /etc/miaou/defaults.yaml
  313. fi
  314. check_credential
  315. echo "successfully checked!"
  316. }
  317. ### MAIN
  318. if [[ "${1:-}" == "SESSION_RELOAD_REQUIRED" ]]; then
  319. SESSION_RELOAD_REQUIRED=true
  320. shift
  321. else
  322. SESSION_RELOAD_REQUIRED=false
  323. fi
  324. if [[ "${1:-}" == "shellenv" ]]; then
  325. unset PREFIX
  326. echo "export MIAOU_BASEDIR=$MIAOU_BASEDIR"
  327. echo "export PATH=\"\$MIAOU_BASEDIR/scripts\":\$PATH"
  328. else
  329. . "$MIAOU_BASEDIR/lib/init.sh"
  330. trap 'status=$?; on_exit; exit $status' EXIT
  331. trap 'trap - HUP; on_exit SIGHUP; kill -HUP $$' HUP
  332. trap 'trap - INT; on_exit SIGINT; kill -INT $$' INT
  333. trap 'trap - TERM; on_exit SIGTERM; kill -TERM $$' TERM
  334. PREFIX="miaou"
  335. : $PREFIX
  336. TARGET=${1:-}
  337. CURRENT_USER=$(id -un)
  338. check_target
  339. sudo_required
  340. install_miaou_bash
  341. install_mandatory_commands
  342. prepare_toolbox
  343. add_toolbox_sudoers
  344. prepare_nftables
  345. prepare_lxd "$@"
  346. override_lxd_service_to_reload_nftables
  347. miaou_resolver
  348. miaou_evalfrombashrc
  349. miaou_configfiles
  350. ask_for_credential
  351. prepare_nftables
  352. opt_link
  353. extra_dev_desktop
  354. if [[ "$SESSION_RELOAD_REQUIRED" == false ]]; then
  355. echoinfo "successful installation"
  356. else
  357. echowarn "please reload your session, .bashrc needs to be reloaded!"
  358. fi
  359. fi