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.

302 lines
10 KiB

  1. #!/bin/bash
  2. ## compose: no-hooks
  3. if [ -z "$SERVICE_DATASTORE" ]; then
  4. echo "This script is meant to be run through 'compose' to work properly." >&2
  5. exit 1
  6. fi
  7. version=0.1
  8. usage="$exname [-h|--help] [--force|-f] [TARGET_VERSION]"
  9. help="
  10. USAGE:
  11. $usage
  12. DESCRIPTION:
  13. Migrate the current nextcloud service to given target version. Don't
  14. forget to change your =compose.yml= accordingly afterwards.
  15. EXAMPLES:
  16. $exname 21.0.0
  17. "
  18. no_hint=
  19. force=
  20. target=
  21. while [ "$1" ]; do
  22. case "$1" in
  23. "--help"|"-h")
  24. print_help >&2
  25. exit 0
  26. ;;
  27. "--force"|"-f")
  28. force=yes
  29. ;;
  30. "--no-hint")
  31. no_hint=yes
  32. ;;
  33. --*|-*)
  34. err "Unexpected optional argument '$1'"
  35. print_usage >&2
  36. exit 1
  37. ;;
  38. *)
  39. [ -z "$target" ] && { target=$1 ; shift ; continue ; }
  40. err "Unexpected positional argument '$1'"
  41. print_usage >&2
  42. exit 1
  43. ;;
  44. esac
  45. shift
  46. done
  47. nextcloud:config:version() {
  48. for f in {"$SERVICE_CONFIGSTORE","$SERVICE_DATASTORE"}/var/www/html/config/config.php; do
  49. if [ -e "$f" ]; then
  50. cat "$f"
  51. break
  52. fi
  53. done |
  54. grep "'version' =>" |
  55. cut -f 4 -d \' |
  56. cut -f 1-3 -d .
  57. }
  58. nextcloud:code:version() {
  59. cat "$SERVICE_DATASTORE/var/www/html/version.php" |
  60. grep 'VersionString =' |
  61. cut -f 3 -d ' ' |
  62. cut -f 2 -d \'
  63. }
  64. current_image_version="${DOCKER_BASE_IMAGE#*:}"
  65. current_image_version="${current_image_version%-myc}"
  66. if ! [[ "$current_image_version" =~ ^[0-9]+.[0-9]+.[0-9]+$ ]]; then
  67. err "Current nextcloud version '$current_image_version' is unsupported yet."
  68. exit 1
  69. fi
  70. if ! [ -e "$SERVICE_DATASTORE/var/www/html/version.php" ]; then
  71. err "No code seem to have been deployed yet in datastore." \
  72. "This is not supported yet."
  73. exit 1
  74. fi
  75. current_code_version=$(nextcloud:code:version)
  76. if [ "$current_code_version" != "$current_image_version" ]; then
  77. err "Current code version ${WHITE}$current_code_version${NORMAL}" \
  78. "mismatch with current image version" \
  79. "${WHITE}$current_image_version${NORMAL}"
  80. exit 1
  81. fi
  82. current_config_version=$(nextcloud:config:version)
  83. info "Current config version: ${WHITE}$current_config_version${NORMAL}"
  84. if [ "$current_config_version" != "$current_code_version" ]; then
  85. warn "Current config version ${WHITE}$current_config_version${NORMAL}" \
  86. "mismatch with current code version" \
  87. "${WHITE}$current_code_version${NORMAL}"
  88. echo " Will use the config version as reference for upgrade." >&2
  89. fi
  90. last_available_versions=(
  91. $(DEBUG= docker:tags:fetch docker.0k.io/nextcloud 30 '[0-9]+\.[0-9+]\.[0-9]+-myc$' |
  92. sed -r 's/-myc$//g' |
  93. sort -rV)
  94. )
  95. ## XXXvlab: put this in kal-shlib-common
  96. version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
  97. last_upgradable_versions=()
  98. for v in "${last_available_versions[@]}"; do
  99. if version_gt "$v" "$current_config_version"; then
  100. last_upgradable_versions+=("$v")
  101. fi
  102. done
  103. docker_version=$(docker info --format '{{.ServerVersion}}')
  104. last_compatible_versions=()
  105. for v in "${last_upgradable_versions[@]}"; do
  106. if version_gt "$docker_version" 20.10.0; then
  107. last_compatible_versions+=("$v")
  108. continue
  109. fi
  110. if version_gt "26.99.99" "$v"; then
  111. last_compatible_versions+=("$v")
  112. fi
  113. done
  114. if [ "${#last_upgradable_versions[@]}" == 0 ]; then
  115. info "${DARKYELLOW}nextcloud${NORMAL} is already ${GREEN}up-to-date${NORMAL}."
  116. exit 0
  117. fi
  118. if [ -z "$target" ]; then
  119. info "Target latest version: ${WHITE}${last_available_versions[0]}${NORMAL}"
  120. target=${last_upgradable_versions[0]}
  121. else
  122. if [[ " ${last_available_versions[*]} " != *" $target "* ]]; then
  123. err "Invalid version ${WHITE}$target${NORMAL} selected, please specify one of:"
  124. for v in "${last_upgradable_versions[@]}"; do
  125. echo " - $v"
  126. done >&2
  127. exit 1
  128. fi
  129. info "Target version ${WHITE}$target${NORMAL}"
  130. fi
  131. if [[ " ${last_compatible_versions[*]} " != *" $target "* ]]; then
  132. err "Sorry, ${DARKYELLOW}$SERVICE_NAME${NORMAL} ${WHITE}$target${NORMAL}" \
  133. "require docker version >= ${WHITE}20.10${NORMAL} (current: $docker_version)"
  134. echo " Nextcloud versions <= ${WHITE}27${NORMAL} are still supported." >&2
  135. echo " You can specify one of:" >&2
  136. for v in "${last_compatible_versions[@]}"; do
  137. echo " - $v" >&2
  138. done
  139. exit 1
  140. fi
  141. upgrade_path=($(echo "${last_upgradable_versions[*]}" | tr ' ' '\n' | uniq -w 3 | sort -V))
  142. containers="$(get_running_containers_for_service "$SERVICE_NAME")"
  143. container_stopped=()
  144. if [ -n "$containers" ]; then
  145. #err "Running container(s) for $DARKYELLOW$SERVICE_NAME$NORMAL are still running:"
  146. for container in $containers; do
  147. docker stop "$container" >/dev/null || {
  148. err "Failed to stop container '$container'."
  149. exit 1
  150. }
  151. docker rm "$container" > /dev/null || {
  152. err "Couldn't delete container '$container'."
  153. }
  154. container_stopped+=("$container")
  155. done
  156. fi
  157. ## XXXvlab: taking first container is probably not a good idea
  158. container="$(echo "$containers" | head -n 1)"
  159. settmpdir MIGRATION_TMPDIR
  160. set -o pipefail
  161. for image_version in "${upgrade_path[@]}"; do
  162. while true; do
  163. patched=()
  164. current_code_version=$(nextcloud:code:version)
  165. current_config_version=$(nextcloud:config:version)
  166. if [ "$current_config_version" == "$image_version" ]; then
  167. err "Unexpected step where config version ${WHITE}$current_config_version${NORMAL} is same than image version"
  168. exit 1
  169. fi
  170. if ! version_gt "$image_version" "$current_config_version"; then
  171. err "Unexpected step where config version ${WHITE}$current_config_version${NORMAL} is greater than image version ${WHITE}$image_version${NORMAL}"
  172. exit 1
  173. fi
  174. if (( ${image_version%%.*} - ${current_config_version%%.*} > 1 )); then
  175. err "Unexpected step where config version ${WHITE}$current_config_version${NORMAL} is more than one major version less than image version ${WHITE}$image_version${NORMAL}"
  176. exit 1
  177. fi
  178. docker rmi "docker.0k.io/nextcloud:${current_config_version}-myc" >/dev/null 2>&1 || true
  179. if [ "$current_code_version" == "$image_version" ]; then
  180. ## Code already setup, we need to call ``occ upgrade`` by our selves
  181. info "Upgrading ${WHITE}$current_config_version${NORMAL} => ${WHITE}$image_version${NORMAL} (db)"
  182. compose --no-hooks \
  183. --add-compose-content="$SERVICE_NAME:
  184. docker-compose:
  185. image: docker.0k.io/nextcloud:${image_version}-myc" \
  186. run --rm \
  187. -u www-data --entrypoint /var/www/html/occ "$SERVICE_NAME" \
  188. upgrade 2>&1 |
  189. tee "$MIGRATION_TMPDIR/migration.log"
  190. errlvl="$?"
  191. else
  192. ## Code will be upgraded
  193. info "Upgrading ${WHITE}$current_config_version${NORMAL} => ${WHITE}$image_version${NORMAL} (code, db)"
  194. compose --no-hooks \
  195. --add-compose-content="$SERVICE_NAME:
  196. docker-compose:
  197. image: docker.0k.io/nextcloud:${image_version}-myc" \
  198. run --rm \
  199. -v "$CHARM_PATH"/src/fake-apache:/usr/bin/apache \
  200. --entrypoint /entrypoint.sh "$SERVICE_NAME" apache 2>&1 |
  201. tee "$MIGRATION_TMPDIR/migration.log"
  202. errlvl="$?"
  203. fi
  204. [ "$errlvl" == 0 ] && continue 2
  205. ##
  206. ## Damage control, there are some things we can solve
  207. ##
  208. if grep "^Update failed" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1; then
  209. ## XXXvlab: this comes from and should move to onlyoffice charm in
  210. ## some way.
  211. if grep "Update app onlyoffice" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1 && (
  212. grep "SQLSTATE" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1 ||
  213. grep "^Database error when running migration latest for app onlyoffice" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1 ); then
  214. if [ -e "$DATASTORE"/"$SERVICE_NAME/var/www/html/custom_apps/onlyoffice/lib/Migration/Version070400Date20220607111111.php" ]; then
  215. patch="$CHARM_PATH/../onlyoffice/src/patch/00-onlyoffice-nextcloud.patch"
  216. if ! [[ " ${patched[*]} " == *" $patch "* ]]; then
  217. if (
  218. cd "$DATASTORE"/"$SERVICE_NAME/var/www/html/custom_apps/onlyoffice/";
  219. patch -Np1 --dry-run < "$patch" ); then
  220. info "Found OnlyOffice issue, correcting it, and retrying."
  221. (
  222. cd "$DATASTORE"/"$SERVICE_NAME/var/www/html/custom_apps/onlyoffice/";
  223. patch -Np1 < "$patch"
  224. ) || exit 1
  225. patched+=("$patch")
  226. continue
  227. fi
  228. fi
  229. fi
  230. fi
  231. fi
  232. err "Upgrade to ${WHITE}$image_version${NORMAL} ${DARKRED}failed${NORMAL}. Aborting."
  233. exit 1
  234. done
  235. done
  236. if grep "^Nextcloud is in maintenance mode" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1; then
  237. info "Forcing maintenance mode off"
  238. compose --no-hooks \
  239. --add-compose-content="$SERVICE_NAME:
  240. docker-compose:
  241. image: docker.0k.io/nextcloud:${target}-myc" \
  242. run --rm \
  243. -u www-data --entrypoint /var/www/html/occ "$SERVICE_NAME" \
  244. maintenance:mode --off
  245. fi
  246. info "Successfully upgraded from ${WHITE}$current_config_version${NORMAL} to ${WHITE}$target${NORMAL}"
  247. if [ -z "$no_hint" ]; then
  248. cat <<EOF >&2
  249. Don't forget to force the version in your \`\`compose.yml\`\`. For instance:
  250. ${DARKYELLOW}$SERVICE_NAME${NORMAL}:
  251. ${DARKGRAY}# ...${NORMAL}
  252. ${WHITE}docker-compose${NORMAL}:
  253. ${WHITE}image${NORMAL}: docker.0k.io/nextcloud:${target}-myc
  254. ${DARKGRAY}# ...${NORMAL}
  255. EOF
  256. fi