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

10 months ago
10 months ago
8 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 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