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.

154 lines
5.3 KiB

  1. #!/bin/bash
  2. ## Init is run on host
  3. ## For now it is run every time the script is launched, but
  4. ## it should be launched only once after build.
  5. ## Accessible variables are:
  6. ## - SERVICE_NAME Name of current service
  7. ## - DOCKER_BASE_IMAGE Base image from which this service might be built if any
  8. ## - SERVICE_DATASTORE Location on host of the DATASTORE of this service
  9. ## - SERVICE_CONFIGSTORE Location on host of the CONFIGSTORE of this service
  10. set -e
  11. service_def=$(get_compose_service_def "$SERVICE_NAME")
  12. admin_keys=$(echo "$service_def" | shyaml -y get-value options.admin 2>/dev/null) || {
  13. err "You must specify a ${WHITE}admin${NORMAL} struct in ${DARKYELLOW}$SERVICE_NAME${NORMAL}'s options"
  14. exit 1
  15. }
  16. [ "$(echo "$admin_keys" | shyaml -y get-type 2>/dev/null)" == "struct" ] || {
  17. err "Invalid value type for ${WHITE}admin${NORMAL} in" \
  18. "${DARKYELLOW}$SERVICE_NAME${NORMAL}'s options, please provide a struct"
  19. exit 1
  20. }
  21. rebuild-config() {
  22. rm -rf "$SERVICE_CONFIGSTORE/etc/rsync/keys/admin"
  23. mkdir -p "$host_path_key"
  24. while read-0 ident keys; do
  25. ident=$(e "$ident" | shyaml get-value)
  26. if ! [[ "$ident" =~ ^[a-zA-Z0-9._-]+$ ]]; then
  27. err "Invalid identifier '$ident'," \
  28. "please use only alphanumerical char, dots, dash or underscores."
  29. exit 1
  30. fi
  31. debug "Setting access keys for ${ident}"
  32. [ "$(echo "$keys" | shyaml -y get-type 2>/dev/null)" == "sequence" ] || {
  33. err "Invalid value type for ${WHITE}admin.$ident${NORMAL}, please provide a sequence"
  34. echo " Received: '$keys'" >&2
  35. exit 1
  36. }
  37. while read-0 key; do
  38. echo "command=\"/usr/local/sbin/ssh-admin-cmd-validate \\\"$ident\\\"\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $key"
  39. done < <(echo "$keys" | shyaml get-values-0) | file_put "$host_path_key/$ident/.ssh/authorized_keys"
  40. done < <(echo "$admin_keys" | shyaml -y key-values-0)
  41. mkdir -p "${CONTROL_USERS_FILE%/*}" || return 1
  42. e "$control_users" > "$CONTROL_USERS_FILE"
  43. }
  44. is_btrfs_subvolume() {
  45. local dir=$1
  46. [ "$(stat -f --format="%T" "$dir")" == "btrfs" ] || return 1
  47. inode="$(stat --format="%i" "$dir")"
  48. case "$inode" in
  49. 2|256)
  50. return 0;;
  51. *)
  52. return 1;;
  53. esac
  54. }
  55. local_path_key=/etc/rsync/keys/admin
  56. host_path_key="$SERVICE_CONFIGSTORE${local_path_key}"
  57. CONTROL_USERS_FILE="$SERVICE_DATASTORE/.control-pass"
  58. ## Was it already properly propagated to database ?
  59. control_users=$(H "${admin_keys}" "$(declare -f "rebuild-config")")
  60. if ! out=$(stat -f -c %T "$SERVICE_DATASTORE"/var/log 2>&1); then
  61. err "Command 'stat' failed with error:"
  62. echo "$out" | prefix " ${GRAY}|${NORMAL} " >&2
  63. exit 1
  64. fi
  65. compose_fragments=""
  66. if [ "$out" == "btrfs" ]; then
  67. ## We'll need to add SYS_ADMIN capability to the container to
  68. ## allow it to delete snapshots
  69. compose_fragments+="\
  70. cap_add:
  71. - SYS_ADMIN
  72. "
  73. RSYNC_LOG_PATH="$SERVICE_DATASTORE/var/log/rsync"
  74. if ! is_btrfs_subvolume "$RSYNC_LOG_PATH"; then
  75. previous_contents=
  76. if [ -e "$RSYNC_LOG_PATH" ]; then
  77. previous_contents=1
  78. info "Directory '$RSYNC_LOG_PATH' exists but is not a btrfs subvolume."
  79. ## we want to keep the data, so we'll move it to a temporary location
  80. mv "$RSYNC_LOG_PATH" "${RSYNC_LOG_PATH}.bak"
  81. fi
  82. if ! out=$(btrfs subvolume create "$RSYNC_LOG_PATH" 2>&1); then
  83. err "Command 'btrfs subvolume create' failed with error:"
  84. echo "$out" | prefix " ${GRAY}|${NORMAL} " >&2
  85. if [ -n "$previous_contents" ]; then
  86. info "Restoring previous contents of '$RSYNC_LOG_PATH'"
  87. mv "${RSYNC_LOG_PATH}.bak" "$RSYNC_LOG_PATH" || exit 1
  88. fi
  89. exit 1
  90. fi
  91. if [ -n "$previous_contents" ]; then
  92. info "Moving previous contents of '$RSYNC_LOG_PATH' into the new subvolume."
  93. (
  94. ## avoid sending our env to find,
  95. ## to prevent any "The environment is too large for exec" error
  96. env -i PATH=/bin:/usr/bin \
  97. find "${RSYNC_LOG_PATH}.bak" \
  98. -mindepth 1 -maxdepth 1 \
  99. -exec cp -a {} "$RSYNC_LOG_PATH/" \;
  100. ) && rm -rf "${RSYNC_LOG_PATH}.bak" || {
  101. err "Failed to copy previous contents of '$RSYNC_LOG_PATH' into the new subvolume."
  102. rmdir "$RSYNC_LOG_PATH" || {
  103. err "Failed to delete the newly created subvolume."
  104. echo " Couldn't restore previous state !!" >&2
  105. exit 1
  106. }
  107. mv "${RSYNC_LOG_PATH}.bak" "$RSYNC_LOG_PATH" || {
  108. err "Failed to restore previous contents of '$RSYNC_LOG_PATH'."
  109. echo " Couldn't restore previous state !!" >&2
  110. exit 1
  111. }
  112. exit 1
  113. }
  114. fi
  115. fi
  116. fi
  117. init-config-add "\
  118. $SERVICE_NAME:
  119. volumes:
  120. - $host_path_key:$local_path_key
  121. labels:
  122. - compose.config_hash=$control_users
  123. $compose_fragments
  124. "
  125. if [ -e "$CONTROL_USERS_FILE" ] && [ "$control_users" == "$(cat "$CONTROL_USERS_FILE")" ]; then
  126. exit 0
  127. fi
  128. rebuild-config