feat(easy-docker): migrate sites after app install

This commit is contained in:
RocketQuack 2026-04-01 16:15:10 +02:00
parent da905fb1c4
commit 8d9b855ff4
4 changed files with 70 additions and 84 deletions

View file

@ -259,7 +259,6 @@ install_stack_apps_on_site() {
"${stack_dir}" \ "${stack_dir}" \
"single-site" \ "single-site" \
"${site_name}" \ "${site_name}" \
"apps_installing" \
"${installed_app_lines}" \ "${installed_app_lines}" \
"install-apps" \ "install-apps" \
"" \ "" \
@ -274,6 +273,26 @@ install_stack_apps_on_site() {
return 0 return 0
} }
run_stack_site_migrate() {
local stack_dir="${1}"
local site_name="${2}"
local migrate_command=""
local migrate_output=""
migrate_command="$(
printf "bench --site %s migrate" \
"$(shell_quote_site_command_arg "${site_name}")"
)"
if ! run_stack_backend_bash_command_capture migrate_output "${stack_dir}" "${migrate_command}"; then
EASY_DOCKER_SITE_ERROR_DETAIL="$(printf "bench migrate failed for '%s'." "${site_name}")"
capture_stack_site_error_log "${stack_dir}" "site-migrate-error" "${migrate_output}" >/dev/null 2>&1 || true
return 64
fi
return 0
}
bootstrap_first_stack_site() { bootstrap_first_stack_site() {
local stack_dir="${1}" local stack_dir="${1}"
local site_name="${2}" local site_name="${2}"
@ -283,6 +302,7 @@ bootstrap_first_stack_site() {
local installed_app_lines="" local installed_app_lines=""
local site_create_status=0 local site_create_status=0
local app_install_status=0 local app_install_status=0
local site_migrate_status=0
local cleanup_status=0 local cleanup_status=0
if ! is_safe_stack_site_cleanup_name "${site_name}"; then if ! is_safe_stack_site_cleanup_name "${site_name}"; then
@ -315,7 +335,7 @@ bootstrap_first_stack_site() {
created_at="$(get_current_utc_timestamp)" created_at="$(get_current_utc_timestamp)"
updated_at="${created_at}" updated_at="${created_at}"
if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "requested" "" "create-site" "" "" "${created_at}" "${updated_at}"; then if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "" "create-site" "" "" "${created_at}" "${updated_at}"; then
return 58 return 58
fi fi
@ -339,7 +359,7 @@ bootstrap_first_stack_site() {
fi fi
updated_at="${created_at}" updated_at="${created_at}"
if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "creating" "" "create-site" "" "" "${created_at}" "${updated_at}"; then if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "" "create-site" "" "" "${created_at}" "${updated_at}"; then
return 58 return 58
fi fi
@ -365,7 +385,7 @@ bootstrap_first_stack_site() {
fi fi
updated_at="$(get_current_utc_timestamp)" updated_at="$(get_current_utc_timestamp)"
if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "created" "" "create-site" "" "" "${created_at}" "${updated_at}"; then if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "" "create-site" "" "" "${created_at}" "${updated_at}"; then
return 58 return 58
fi fi
@ -400,8 +420,23 @@ bootstrap_first_stack_site() {
return "${app_install_status}" return "${app_install_status}"
fi fi
if run_stack_site_migrate "${stack_dir}" "${site_name}"; then
:
else
site_migrate_status=$?
case "${site_migrate_status}" in
64)
mark_stack_site_failed "${stack_dir}" "${site_name}" "${installed_app_lines}" "migrate-site" "${EASY_DOCKER_SITE_ERROR_DETAIL:-Site migration failed.}" "${EASY_DOCKER_SITE_ERROR_LOG_PATH}" "${created_at}" >/dev/null 2>&1 || true
;;
*)
mark_stack_site_failed "${stack_dir}" "${site_name}" "${installed_app_lines}" "migrate-site" "Unknown site migration failure." "${EASY_DOCKER_SITE_ERROR_LOG_PATH}" "${created_at}" >/dev/null 2>&1 || true
;;
esac
return "${site_migrate_status}"
fi
updated_at="$(get_current_utc_timestamp)" updated_at="$(get_current_utc_timestamp)"
if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "ready" "${installed_app_lines}" "install-apps" "" "" "${created_at}" "${updated_at}"; then if ! persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "${installed_app_lines}" "migrate-site" "" "" "${created_at}" "${updated_at}"; then
return 58 return 58
fi fi

View file

@ -75,10 +75,10 @@ get_stack_site_name() {
get_metadata_site_string_field "${stack_dir}/metadata.json" "name" get_metadata_site_string_field "${stack_dir}/metadata.json" "name"
} }
get_stack_site_state() { get_stack_site_last_error() {
local stack_dir="${1}" local stack_dir="${1}"
get_metadata_site_string_field "${stack_dir}/metadata.json" "state" get_metadata_site_string_field "${stack_dir}/metadata.json" "last_error"
} }
get_stack_site_created_at() { get_stack_site_created_at() {
@ -107,78 +107,29 @@ stack_has_site_record() {
stack_has_site_configured() { stack_has_site_configured() {
local stack_dir="${1}" local stack_dir="${1}"
local site_state=""
site_state="$(get_stack_site_state "${stack_dir}" || true)"
case "${site_state}" in
created | apps_installing | ready)
return 0
;;
*)
return 1
;;
esac
}
get_stack_site_status_label() {
local result_var="${1}"
local stack_dir="${2}"
local site_state=""
local site_name="" local site_name=""
local site_status_label="" local last_error=""
site_state="$(get_stack_site_state "${stack_dir}" || true)"
site_name="$(get_stack_site_name "${stack_dir}" || true)" site_name="$(get_stack_site_name "${stack_dir}" || true)"
last_error="$(get_stack_site_last_error "${stack_dir}" || true)"
case "${site_state}" in if [ -n "${site_name}" ] && [ -z "${last_error}" ]; then
"") return 0
site_status_label="Not configured"
;;
requested)
site_status_label="Requested"
;;
creating)
site_status_label="Creating"
;;
created)
site_status_label="Created"
;;
apps_installing)
site_status_label="Installing apps"
;;
ready)
site_status_label="Ready"
;;
failed)
site_status_label="Failed"
;;
*)
site_status_label="${site_state}"
;;
esac
if [ -n "${site_name}" ]; then
site_status_label="${site_status_label} (${site_name})"
fi fi
printf -v "${result_var}" "%s" "${site_status_label}" return 1
return 0
} }
get_stack_site_menu_entry() { get_stack_site_menu_entry() {
local result_var="${1}" local result_var="${1}"
local stack_dir="${2}" local stack_dir="${2}"
local site_name="" local site_name=""
local site_status_label=""
local menu_entry=""
site_name="$(get_stack_site_name "${stack_dir}" || true)" site_name="$(get_stack_site_name "${stack_dir}" || true)"
if [ -z "${site_name}" ]; then if [ -z "${site_name}" ]; then
return 1 return 1
fi fi
get_stack_site_status_label site_status_label "${stack_dir}" printf -v "${result_var}" "%s" "${site_name}"
menu_entry="$(printf "%s | %s" "${site_name}" "${site_status_label}")"
printf -v "${result_var}" "%s" "${menu_entry}"
return 0 return 0
} }

View file

@ -33,21 +33,19 @@ build_stack_site_metadata_json_object() {
local result_var="${1}" local result_var="${1}"
local site_mode="${2:-single-site}" local site_mode="${2:-single-site}"
local site_name="${3:-}" local site_name="${3:-}"
local site_state="${4:-not_created}" local apps_installed_lines="${4:-}"
local apps_installed_lines="${5:-}" local last_action="${5:-}"
local last_action="${6:-}" local last_error="${6:-}"
local last_error="${7:-}" local error_log_path="${7:-}"
local error_log_path="${8:-}" local created_at="${8:-}"
local created_at="${9:-}" local updated_at="${9:-}"
local updated_at="${10:-}"
local apps_installed_json_array="" local apps_installed_json_array=""
build_stack_site_apps_installed_json_array apps_installed_json_array "${apps_installed_lines}" build_stack_site_apps_installed_json_array apps_installed_json_array "${apps_installed_lines}"
printf -v "${result_var}" '{\n "mode": "%s",\n "name": "%s",\n "state": "%s",\n "apps_installed": %s,\n "last_action": "%s",\n "last_error": "%s",\n "error_log_path": "%s",\n "created_at": "%s",\n "updated_at": "%s"\n }' \ printf -v "${result_var}" '{\n "mode": "%s",\n "name": "%s",\n "apps_installed": %s,\n "last_action": "%s",\n "last_error": "%s",\n "error_log_path": "%s",\n "created_at": "%s",\n "updated_at": "%s"\n }' \
"$(json_escape_string "${site_mode}")" \ "$(json_escape_string "${site_mode}")" \
"$(json_escape_string "${site_name}")" \ "$(json_escape_string "${site_name}")" \
"$(json_escape_string "${site_state}")" \
"${apps_installed_json_array}" \ "${apps_installed_json_array}" \
"$(json_escape_string "${last_action}")" \ "$(json_escape_string "${last_action}")" \
"$(json_escape_string "${last_error}")" \ "$(json_escape_string "${last_error}")" \
@ -60,13 +58,12 @@ persist_stack_site_metadata() {
local stack_dir="${1}" local stack_dir="${1}"
local site_mode="${2:-single-site}" local site_mode="${2:-single-site}"
local site_name="${3:-}" local site_name="${3:-}"
local site_state="${4:-not_created}" local apps_installed_lines="${4:-}"
local apps_installed_lines="${5:-}" local last_action="${5:-}"
local last_action="${6:-}" local last_error="${6:-}"
local last_error="${7:-}" local error_log_path="${7:-}"
local error_log_path="${8:-}" local created_at="${8:-}"
local created_at="${9:-}" local updated_at="${9:-}"
local updated_at="${10:-}"
local metadata_path="" local metadata_path=""
local metadata_tmp_path="" local metadata_tmp_path=""
local site_json_object="" local site_json_object=""
@ -77,7 +74,7 @@ persist_stack_site_metadata() {
return 1 return 1
fi fi
build_stack_site_metadata_json_object site_json_object "${site_mode}" "${site_name}" "${site_state}" "${apps_installed_lines}" "${last_action}" "${last_error}" "${error_log_path}" "${created_at}" "${updated_at}" build_stack_site_metadata_json_object site_json_object "${site_mode}" "${site_name}" "${apps_installed_lines}" "${last_action}" "${last_error}" "${error_log_path}" "${created_at}" "${updated_at}"
if ! awk -v site_object="${site_json_object}" ' if ! awk -v site_object="${site_json_object}" '
BEGIN { BEGIN {
@ -167,7 +164,7 @@ mark_stack_site_failed() {
local updated_at="" local updated_at=""
updated_at="$(get_current_utc_timestamp)" updated_at="$(get_current_utc_timestamp)"
persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "failed" "${apps_installed_lines}" "${last_action}" "${last_error}" "${error_log_path}" "${created_at}" "${updated_at}" persist_stack_site_metadata "${stack_dir}" "single-site" "${site_name}" "${apps_installed_lines}" "${last_action}" "${last_error}" "${error_log_path}" "${created_at}" "${updated_at}"
} }
clear_stack_site_metadata() { clear_stack_site_metadata() {
@ -175,5 +172,5 @@ clear_stack_site_metadata() {
local updated_at="" local updated_at=""
updated_at="$(get_current_utc_timestamp)" updated_at="$(get_current_utc_timestamp)"
persist_stack_site_metadata "${stack_dir}" "single-site" "" "not_created" "" "delete-site" "" "" "" "${updated_at}" persist_stack_site_metadata "${stack_dir}" "single-site" "" "" "delete-site" "" "" "" "${updated_at}"
} }

View file

@ -32,7 +32,7 @@ handle_manage_stack_site_flow() {
show_warning_message "Creating the first site for stack: ${stack_name}" show_warning_message "Creating the first site for stack: ${stack_name}"
if bootstrap_first_stack_site "${stack_dir}" "${site_name}" "${admin_password}"; then if bootstrap_first_stack_site "${stack_dir}" "${site_name}" "${admin_password}"; then
show_warning_and_wait "Site created successfully and selected stack apps were installed: ${site_name}" 3 show_warning_and_wait "Site created successfully, selected stack apps were installed, and bench migrate completed: ${site_name}" 3
continue continue
else else
site_flow_status=$? site_flow_status=$?
@ -61,7 +61,7 @@ handle_manage_stack_site_flow() {
show_warning_and_wait "Site bootstrap currently supports only MariaDB-backed single-host stacks." 4 show_warning_and_wait "Site bootstrap currently supports only MariaDB-backed single-host stacks." 4
;; ;;
58) 58)
show_warning_and_wait "The site state could not be written to metadata.json." 4 show_warning_and_wait "The site metadata could not be written to metadata.json." 4
;; ;;
59) 59)
show_warning_and_wait "Cannot create site: stack services are not ready yet. Wait and try again." 4 show_warning_and_wait "Cannot create site: stack services are not ready yet. Wait and try again." 4
@ -78,6 +78,9 @@ handle_manage_stack_site_flow() {
63) 63)
show_warning_and_wait "Cannot install the selected stack apps because at least one app is missing from the backend image. ${EASY_DOCKER_SITE_ERROR_DETAIL} ${EASY_DOCKER_SITE_ERROR_LOG_PATH:+See ${stack_dir}/${EASY_DOCKER_SITE_ERROR_LOG_PATH}}" 7 show_warning_and_wait "Cannot install the selected stack apps because at least one app is missing from the backend image. ${EASY_DOCKER_SITE_ERROR_DETAIL} ${EASY_DOCKER_SITE_ERROR_LOG_PATH:+See ${stack_dir}/${EASY_DOCKER_SITE_ERROR_LOG_PATH}}" 7
;; ;;
64)
show_warning_and_wait "The site was created and apps were installed, but bench migrate failed. ${EASY_DOCKER_SITE_ERROR_DETAIL:-Check the output above.} ${EASY_DOCKER_SITE_ERROR_LOG_PATH:+See ${stack_dir}/${EASY_DOCKER_SITE_ERROR_LOG_PATH}}" 7
;;
*) *)
show_warning_and_wait "Site bootstrap failed (${site_flow_status})." 4 show_warning_and_wait "Site bootstrap failed (${site_flow_status})." 4
;; ;;
@ -139,7 +142,7 @@ handle_manage_stack_site_flow() {
show_warning_and_wait "Cannot delete site because stack metadata, env, or compose inputs are incomplete." 4 show_warning_and_wait "Cannot delete site because stack metadata, env, or compose inputs are incomplete." 4
;; ;;
58) 58)
show_warning_and_wait "The cleared site state could not be written to metadata.json." 4 show_warning_and_wait "The cleared site metadata could not be written to metadata.json." 4
;; ;;
60) 60)
show_warning_and_wait "Site deletion could not remove all site or database data automatically. Manual cleanup is required." 5 show_warning_and_wait "Site deletion could not remove all site or database data automatically. Manual cleanup is required." 5