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.

195 lines
6.7 KiB

9 months ago
9 months ago
7 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
  1. #!/bin/bash
  2. function check_container_missing() {
  3. if container_exists "$CONTAINER"; then
  4. echoerr "$CONTAINER already created!"
  5. exit 1
  6. fi
  7. }
  8. function usage() {
  9. echo 'USAGE with options:'
  10. echo -e "\t\tlxc-miaou-create <CONTAINER_NAME> -o sameuser[,nesting,ssh]"
  11. }
  12. function check() {
  13. check_container_missing || return 1
  14. return 0
  15. }
  16. function set_options() {
  17. declare -a options=("$@")
  18. length=${#options[@]}
  19. if [[ "$length" -ne 0 ]]; then
  20. if [[ "$length" -ne 2 ]]; then
  21. echoerr "unrecognized options: $@" && usage && exit 30
  22. else
  23. prefix="${options[0]}"
  24. option="${options[1]}"
  25. if [[ "$prefix" == '-o' ]]; then
  26. IFS=',' read -r -a options <<<"$option"
  27. for i in ${options[@]}; do
  28. case "$i" in
  29. sameuser) OPTION_SAMEUSER=true ;;
  30. nesting) OPTION_NESTING=true ;;
  31. ssh) OPTION_SSH=true ;;
  32. *) echoerr "unrecognized options: $@" && usage && exit 32 ;;
  33. esac
  34. done
  35. # echo "OPTION_SAMEUSER=$OPTION_SAMEUSER, OPTION_NESTING=$OPTION_NESTING, OPTION_SSH=$OPTION_SSH"
  36. else
  37. echoerr "unrecognized options prefix: $prefix" && usage && exit 31
  38. fi
  39. fi
  40. shift
  41. fi
  42. }
  43. function create() {
  44. local PREFIX="miaou:create"
  45. if [[ "$OPTION_SAMEUSER" == true ]]; then
  46. miaou_user=$(whoami)
  47. fi
  48. echo -n "creating new container <$CONTAINER> based on image <$CONTAINER_RELEASE>... "
  49. bridge_gw=$(lxc network get lxdbr0 ipv4.address | cut -d'/' -f1)
  50. packages=(git file bc bash-completion)
  51. [[ "$OPTION_SSH" == true ]] && packages+=(openssh-server)
  52. packages_string=$(join ', ' "${packages[@]}")
  53. timezone=$(cat /etc/timezone)
  54. debian_repo=$(grep ^deb /etc/apt/sources.list | head -n1 | cut -d '/' -f3)
  55. user_data="$(
  56. cat <<EOF
  57. #cloud-config
  58. timezone: '$timezone'
  59. apt:
  60. preserve_sources_list: false
  61. conf: |
  62. Acquire::Retries "60";
  63. DPkg::Lock::Timeout "60";
  64. primary:
  65. - arches: [default]
  66. uri: http://$debian_repo/debian
  67. security:
  68. - arches: [default]
  69. uri: http://$debian_repo/debian-security
  70. sources_list: |
  71. # generated by miaou
  72. deb \$PRIMARY \$RELEASE main
  73. deb \$PRIMARY \$RELEASE-updates main
  74. deb \$SECURITY \$RELEASE-security main
  75. package_update: true
  76. package_upgrade: true
  77. package_reboot_if_required: true
  78. packages: [ $packages_string ]
  79. write_files:
  80. - path: /etc/sudoers.d/10-add_TOOLBOX_to_secure_path
  81. content: >
  82. Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/TOOLBOX"
  83. runcmd:
  84. - [ systemctl, mask, systemd-hostnamed.service ]
  85. - [ systemctl, disable, e2scrub_reap.service ]
  86. - [ systemctl, disable, systemd-resolved.service, --now ]
  87. - [ systemctl, reset-failed ]
  88. - [ rm, /etc/resolv.conf]
  89. - [ rm, /etc/sudoers.d/90-cloud-init-users]
  90. - "echo nameserver $bridge_gw > /etc/resolv.conf"
  91. final_message: "Container from datasource \$datasource is finally up, after \$UPTIME seconds"
  92. EOF
  93. )"
  94. lxc init local:debian/$CONTAINER_RELEASE/cloud "$CONTAINER" --config user.user-data="$user_data" -q
  95. # allow directory `SHARED` to be read-write mounted
  96. lxc config set "$CONTAINER" raw.idmap "both $(id -u) 0" -q
  97. mkdir -p "$HOME/LXD/SHARED/$CONTAINER"
  98. lxc config device add "$CONTAINER" SHARED disk source="$HOME/LXD/SHARED/$CONTAINER" path=/mnt/SHARED -q
  99. lxc config device add "$CONTAINER" TOOLBOX disk source=/TOOLBOX path=/TOOLBOX readonly=true -q
  100. lxc config device add "$CONTAINER" MIAOU_BASH disk source=$(realpath /opt/miaou-bash) path=/opt/miaou-bash readonly=true -q
  101. # environment variables
  102. lxc config set "$CONTAINER" environment.PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/miaou-bash/tools:/TOOLBOX -q
  103. lxc config set "$CONTAINER" environment.container lxc -q
  104. if [[ "$OPTION_NESTING" == true ]]; then
  105. lxc config set "$CONTAINER" security.nesting true -q
  106. lxc config device add "$CONTAINER" miaou disk source=/opt/miaou path=/opt/miaou readonly=true -q
  107. fi
  108. lxc start "$CONTAINER" -q
  109. # initializing miaou-bash
  110. lxc exec "$CONTAINER" -- /opt/miaou-bash/init.sh
  111. # default configuration files (btm,)
  112. lxc exec "$CONTAINER" -- mkdir -p /root/.config/bottom
  113. lxc file push "$MIAOU_BASEDIR/templates/bottom/bottom.toml" "$CONTAINER/root/.config/bottom/bottom.toml" -q
  114. # purge cloud-init after success
  115. attempt=0
  116. max_attempt=10
  117. delay=0.2
  118. while ! lxc exec "$CONTAINER" -- bash -c 'systemd-run -q -p After=cloud-final.service -p Type=oneshot --no-block bash -c "\
  119. cloud-init status --wait &&\
  120. cp /var/lib/cloud/data/status.json /root/cloud-status.json &&\
  121. systemctl stop cloud-{config,final,init-local,init}.service &&\
  122. systemctl disable cloud-{config,final,init-local,init}.service &&\
  123. systemctl stop cloud-config.target cloud-init.target &&\
  124. apt-get purge -y cloud-init &&\
  125. rm -rf /var/lib/cloud && \
  126. userdel -rf debian \
  127. " 2>/dev/null '; do
  128. attempt=$((attempt++))
  129. if [[ $attempt -gt $max_attempt ]]; then
  130. echoerr "systemd unavailable after $(bc <<<"$max_attempt * $delay") seconds"
  131. exit 1
  132. else
  133. sleep $delay
  134. fi
  135. done
  136. if [[ "$OPTION_SAMEUSER" == true ]]; then
  137. if ! lxc exec "$CONTAINER" -- grep "$miaou_user" /etc/passwd; then
  138. lxc exec "$CONTAINER" -- useradd -ms /bin/bash -G sudo "$miaou_user"
  139. fi
  140. if ! lxc exec "$CONTAINER" -- passwd -S "$miaou_user" | cut -d ' ' -f2 | grep -q ^P; then
  141. shadow_passwd=$(load_yaml_from_expanded credential.shadow)
  142. shadow_remainder=$(lxc exec "$CONTAINER" -- bash -c "grep $miaou_user /etc/shadow | cut -d':' -f3-")
  143. lxc exec "$CONTAINER" -- /opt/miaou-bash/tools/append_or_replace "^$miaou_user:.*:" "$miaou_user:$shadow_passwd:$shadow_remainder" /etc/shadow >/dev/null
  144. fi
  145. fi
  146. if [[ "$OPTION_SSH" == true && "$OPTION_SAMEUSER" == true ]]; then
  147. #FIXME: can be fatser due to openssh-server already installed from cloud-init
  148. lxc-miaou-enable-ssh "$CONTAINER" >/dev/null
  149. fi
  150. PREFIX="" echoinfo OK
  151. echo "hint: \`lxc login $CONTAINER [--env user=<USER>]\`"
  152. [[ "$OPTION_SAMEUSER" == true ]] && echo "hint: \`lxc sameuser $CONTAINER\`"
  153. true
  154. }
  155. ## MAIN
  156. . "$MIAOU_BASEDIR/lib/init.sh"
  157. OPTION_SAMEUSER=false
  158. OPTION_NESTING=false
  159. OPTION_SSH=false
  160. PREFIX="miaou"
  161. arg1_required "$@" || (usage && exit 1)
  162. readonly CONTAINER=$1
  163. readonly CONTAINER_RELEASE="bookworm"
  164. shift
  165. set_options "$@"
  166. readonly FULL_OPTIONS="$@"
  167. check
  168. create