From 8d9b855ff450cb7ada935e43b56fb99d4476eccc Mon Sep 17 00:00:00 2001 From: RocketQuack <202538874+Rocket-Quack@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:15:10 +0200 Subject: [PATCH] feat(easy-docker): migrate sites after app install --- .../wizard/common/site/bootstrap/lifecycle.sh | 45 +++++++++++-- .../app/wizard/common/site/metadata/read.sh | 65 +++---------------- .../app/wizard/common/site/metadata/write.sh | 35 +++++----- .../lib/app/wizard/flows/manage/site.sh | 9 ++- 4 files changed, 70 insertions(+), 84 deletions(-) diff --git a/scripts/easy-docker/lib/app/wizard/common/site/bootstrap/lifecycle.sh b/scripts/easy-docker/lib/app/wizard/common/site/bootstrap/lifecycle.sh index 6efb2249..be920cac 100755 --- a/scripts/easy-docker/lib/app/wizard/common/site/bootstrap/lifecycle.sh +++ b/scripts/easy-docker/lib/app/wizard/common/site/bootstrap/lifecycle.sh @@ -259,7 +259,6 @@ install_stack_apps_on_site() { "${stack_dir}" \ "single-site" \ "${site_name}" \ - "apps_installing" \ "${installed_app_lines}" \ "install-apps" \ "" \ @@ -274,6 +273,26 @@ install_stack_apps_on_site() { 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() { local stack_dir="${1}" local site_name="${2}" @@ -283,6 +302,7 @@ bootstrap_first_stack_site() { local installed_app_lines="" local site_create_status=0 local app_install_status=0 + local site_migrate_status=0 local cleanup_status=0 if ! is_safe_stack_site_cleanup_name "${site_name}"; then @@ -315,7 +335,7 @@ bootstrap_first_stack_site() { created_at="$(get_current_utc_timestamp)" 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 fi @@ -339,7 +359,7 @@ bootstrap_first_stack_site() { fi 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 fi @@ -365,7 +385,7 @@ bootstrap_first_stack_site() { fi 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 fi @@ -400,8 +420,23 @@ bootstrap_first_stack_site() { return "${app_install_status}" 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)" - 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 fi diff --git a/scripts/easy-docker/lib/app/wizard/common/site/metadata/read.sh b/scripts/easy-docker/lib/app/wizard/common/site/metadata/read.sh index ace5e3dd..51790f06 100755 --- a/scripts/easy-docker/lib/app/wizard/common/site/metadata/read.sh +++ b/scripts/easy-docker/lib/app/wizard/common/site/metadata/read.sh @@ -75,10 +75,10 @@ get_stack_site_name() { get_metadata_site_string_field "${stack_dir}/metadata.json" "name" } -get_stack_site_state() { +get_stack_site_last_error() { 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() { @@ -107,78 +107,29 @@ stack_has_site_record() { stack_has_site_configured() { 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_status_label="" + local last_error="" - site_state="$(get_stack_site_state "${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 - "") - 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})" + if [ -n "${site_name}" ] && [ -z "${last_error}" ]; then + return 0 fi - printf -v "${result_var}" "%s" "${site_status_label}" - return 0 + return 1 } get_stack_site_menu_entry() { local result_var="${1}" local stack_dir="${2}" local site_name="" - local site_status_label="" - local menu_entry="" site_name="$(get_stack_site_name "${stack_dir}" || true)" if [ -z "${site_name}" ]; then return 1 fi - get_stack_site_status_label site_status_label "${stack_dir}" - menu_entry="$(printf "%s | %s" "${site_name}" "${site_status_label}")" - printf -v "${result_var}" "%s" "${menu_entry}" + printf -v "${result_var}" "%s" "${site_name}" return 0 } diff --git a/scripts/easy-docker/lib/app/wizard/common/site/metadata/write.sh b/scripts/easy-docker/lib/app/wizard/common/site/metadata/write.sh index 1d35697e..15435d57 100755 --- a/scripts/easy-docker/lib/app/wizard/common/site/metadata/write.sh +++ b/scripts/easy-docker/lib/app/wizard/common/site/metadata/write.sh @@ -33,21 +33,19 @@ build_stack_site_metadata_json_object() { local result_var="${1}" local site_mode="${2:-single-site}" local site_name="${3:-}" - local site_state="${4:-not_created}" - local apps_installed_lines="${5:-}" - local last_action="${6:-}" - local last_error="${7:-}" - local error_log_path="${8:-}" - local created_at="${9:-}" - local updated_at="${10:-}" + local apps_installed_lines="${4:-}" + local last_action="${5:-}" + local last_error="${6:-}" + local error_log_path="${7:-}" + local created_at="${8:-}" + local updated_at="${9:-}" local apps_installed_json_array="" 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_name}")" \ - "$(json_escape_string "${site_state}")" \ "${apps_installed_json_array}" \ "$(json_escape_string "${last_action}")" \ "$(json_escape_string "${last_error}")" \ @@ -60,13 +58,12 @@ persist_stack_site_metadata() { local stack_dir="${1}" local site_mode="${2:-single-site}" local site_name="${3:-}" - local site_state="${4:-not_created}" - local apps_installed_lines="${5:-}" - local last_action="${6:-}" - local last_error="${7:-}" - local error_log_path="${8:-}" - local created_at="${9:-}" - local updated_at="${10:-}" + local apps_installed_lines="${4:-}" + local last_action="${5:-}" + local last_error="${6:-}" + local error_log_path="${7:-}" + local created_at="${8:-}" + local updated_at="${9:-}" local metadata_path="" local metadata_tmp_path="" local site_json_object="" @@ -77,7 +74,7 @@ persist_stack_site_metadata() { return 1 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}" ' BEGIN { @@ -167,7 +164,7 @@ mark_stack_site_failed() { local updated_at="" 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() { @@ -175,5 +172,5 @@ clear_stack_site_metadata() { local updated_at="" 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}" } diff --git a/scripts/easy-docker/lib/app/wizard/flows/manage/site.sh b/scripts/easy-docker/lib/app/wizard/flows/manage/site.sh index 6a076ab3..e408a324 100755 --- a/scripts/easy-docker/lib/app/wizard/flows/manage/site.sh +++ b/scripts/easy-docker/lib/app/wizard/flows/manage/site.sh @@ -32,7 +32,7 @@ handle_manage_stack_site_flow() { show_warning_message "Creating the first site for stack: ${stack_name}" 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 else 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 ;; 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) 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) 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 ;; @@ -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 ;; 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) show_warning_and_wait "Site deletion could not remove all site or database data automatically. Manual cleanup is required." 5