diff --git a/devbox/devbox.local/cli/devbox b/devbox/devbox.local/cli/devbox new file mode 100644 index 0000000..fe1ce9d --- /dev/null +++ b/devbox/devbox.local/cli/devbox @@ -0,0 +1,2898 @@ +#!/usr/bin/env bash +# Modifying it manually is not recommended + +# :wrapper.bash3_bouncer +if [[ "${BASH_VERSINFO:-0}" -lt 3 ]]; then + printf "bash version 3 or higher is required\n" >&2 + exit 1 +fi + +# :command.master_script + +# :command.version_command +version_command() { + echo "$version" +} + +upper() { + echo "$1" | tr '[:lower:]' '[:upper:]' +} + +lower() { + echo "$1" | tr '[:upper:]' '[:lower:]' +} + + +# Add a key-value pair to the args array +add_arg() { + local key="$1" + local value="$2" + args_keys+=("$key") + args_values+=("$value") +} + +# Get the value of a key from the args array + +get_arg() { + local key="$1" + local default="${2:-}" + local i + + for i in "${!args_keys[@]}"; do + if [ "${args_keys[$i]}" = "$key" ]; then + echo "${args_values[$i]}" + return 0 + fi + done + echo "$default" + return 1 +} + + +# :command.usage +devbox_usage() { + printf "Command\n" + printf " devbox : DevBox Command Line Tool for managing the local development environment.\n\n" + + printf "Arguments\n" + printf " COMMAND [Required] : Specify the command to execute (e.g., init, deinit, start, stop, status, restart).\n\n" + + printf "Global Arguments\n" + printf " --help, -h : Show this help message and exit.\n" + printf " --version, -v : Show version number.\n\n" + + printf "Examples\n" + printf " Display help for the 'init' command:\n" + printf " devbox init --help\n\n" + printf " Display version information:\n" + printf " devbox --version\n" + echo +} + + +# :command.usage +devbox_init_usage() { + if [[ -n $long_usage ]]; then + printf "Command\n" + printf " devbox init : Initialize the local development environment based on DevBox container.\n\n" + + printf "Arguments\n" + printf " --os -o [Optional] : Specifies the operating system. Default: auto.\n" + printf " --arch -a [Optional] : Specifies the architecture. Default: auto.\n" + printf " --working-home -w [Optional] : Specifies the working home of DevBox CLI. Default: %s/devbox\n" "$HOME" + printf " --devbox-container-name -N [Optional] : Specifies the DevBox container name. Default: devbox.\n" + printf " --devbox-container-port -P [Optional] : Specifies the container port for DevBox SSH access. Default: 22222.\n" + printf " --devbox-image-repo -R [Optional] : Specifies the DevBox container image repository. Default: docker.io/freeleaps.\n" + printf " --devbox-image-name -I [Optional] : Specifies the DevBox container image name. Default: devbox.\n" + printf " --devbox-image-tag -T [Optional] : Specifies the DevBox container image tag. Default: latest.\n" + printf " --devbox-frontend-port -F [Optional] : Specifies the container port for DevBox frontend access. Default: 5173.\n" + printf " --devbox-backend-port -B [Optional] : Specifies the container port for DevBox backend access. Default: 8002.\n" + printf " --freeleaps-username -U [Optional] : Specifies the Freeleaps.com repository username.\n" + printf " --freeleaps-password -X [Optional] : Specifies the Freeleaps.com repository password.\n" + printf " --use-local-component -u [Optional] : Check if using local component or online dev environment. Default: false.\n" + printf " --devsvc-image-repo -D [Optional] : Specifies the repository for devsvc component.\n" + printf " --devsvc-image-name -M [Optional] : Specifies the image name for devsvc component.\n" + printf " --devsvc-image-tag -G [Optional] : Specifies the image tag for devsvc component. Default: latest.\n" + printf " --notification-image-repo -Y [Optional] : Specifies the repository for notification component.\n" + printf " --notification-image-name -K [Optional] : Specifies the image name for notification component.\n" + printf " --notification-image-tag -Z [Optional] : Specifies the image tag for notification component. Default: latest.\n" + printf " --content-image-repo -C [Optional] : Specifies the repository for content component.\n" + printf " --content-image-name -E [Optional] : Specifies the image name for content component.\n" + printf " --content-image-tag -H [Optional] : Specifies the image tag for content component. Default: latest.\n" + printf " --central_storage-image-repo -S [Optional] : Specifies the repository for central_storage component.\n" + printf " --central_storage-image-name -J [Optional] : Specifies the image name for central_storage component.\n" + printf " --central_storage-image-tag -Q [Optional] : Specifies the image tag for central_storage component. Default: latest.\n" + printf " --authentication-image-repo -V [Optional] : Specifies the repository for authentication component.\n" + printf " --authentication-image-name -L [Optional] : Specifies the image name for authentication component.\n" + printf " --authentication-image-tag -W [Optional] : Specifies the image tag for authentication component. Default: latest.\n" + printf " --force -f [Optional] : Force initialization even if resources already exist.\n\n" + + printf "Global Arguments\n" + printf " --help -h : Show this help message and exit.\n\n" + + printf "Examples\n" + printf " Initialize DevBox with Linux OS and ARM64 architecture:\n" + printf " devbox init --os linux --arch arm64 --freeleaps-username alice --freeleaps-password secret\n" + printf " Initialize with custom container settings:\n" + printf " devbox init --devbox-container-name custom-devbox --devbox-container-port 22222 --freeleaps-username alice --freeleaps-password secret\n" + else + printf "devbox init - Initialize the local development environment based on DevBox container.\n\n" + fi +} + +# :command.usage +devbox_deinit_usage() { + if [[ -n $long_usage ]]; then + printf "Command\n" + printf " devbox deinit : De-initialize the local development environment based on DevBox container.\n\n" + + printf "Arguments\n" + printf " --working-home -w [Optional] : Specifies the working home of DevBox CLI. Default: %s/devbox\n" "$HOME" + printf " --clear-logs -l [Optional] : Specifies whether to clear log files. Default: true\n" + printf " --clear-repo -r [Optional] : Specifies whether to delete the source repository. Default: false\n\n" + + printf "Global Arguments\n" + printf " --help, -h : Show this help message and exit.\n\n" + + printf "Examples\n" + printf " De-initialize the local development environment.\n" + printf " devbox deinit\n" + printf " De-initialize with custom working home and options.\n" + printf " devbox deinit --working-home=/tmp/devbox --clear-logs=false --clear-repo=true\n" + else + printf "devbox deinit - De-initialize the local development environment based on DevBox container.\n\n" + fi +} + +# :command.usage +devbox_start_usage() { + if [[ -n $long_usage ]]; then + printf "Command\n" + printf " devbox start : Start the local development environment based on DevBox container.\n\n" + + printf "Arguments\n" + printf " --component COMPONENT [Optional] : Specifies the name of the component to start (e.g., mongodb, rabbitmq, backend, frontend, devsvc, content, central_storage, authentication).\n\n" + printf " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com endpoint to start in the DevBox container.\n\n" + printf "Global Arguments\n" + printf " --help, -h : Show this help message and exit.\n\n" + + printf "Examples\n" + printf " Start all components:\n" + printf " devbox start\n" + printf " Start a specific component (e.g., backend):\n" + printf " devbox start --component=backend\n" + else + printf "devbox start - Start the local development environment based on DevBox container.\n\n" + fi + printf "Alias: s\n" + echo +} + +# :command.usage +devbox_stop_usage() { + if [[ -n $long_usage ]]; then + printf "Command\n" + printf " devbox stop : Stop the local development environment based on DevBox container.\n\n" + printf "Arguments\n" + printf " --component -c [Optional] : Specifies the name of the component to stop (e.g., mongodb, rabbitmq, devbox, devsvc, content, central_storage, authentication).\n\n" + printf "Global Arguments\n" + printf " --help -h : Show this help message and exit.\n\n" + printf "Examples\n" + printf " Stop all components:\n" + printf " devbox stop\n\n" + printf " Stop a specific component (e.g., backend):\n" + printf " devbox stop --component=backend\n" + else + printf "devbox stop - Stop the local development environment based on DevBox container.\n" + fi + echo +} + +# :command.usage +devbox_status_usage() { + if [[ -n $long_usage ]]; then + printf "Command\n" + printf " devbox status : Display the status of the local development environment based on DevBox container.\n\n" + + printf "Arguments\n" + printf " --component -c [Optional] : Specifies the component to show status (e.g., devbox, devsvc, etc.).\n\n" + + printf "Global Arguments\n" + printf " --help -h : Show this help message and exit.\n\n" + + printf "Examples\n" + printf " Display status for all components:\n" + printf " devbox status\n\n" + printf " Display status for a specific component:\n" + printf " devbox status --component=backend\n" + else + printf "devbox status - Display the status of the local development environment based on DevBox container.\n" + fi + echo +} + +# :command.usage +devbox_restart_usage() { + if [[ -n $long_usage ]]; then + printf "Command\n" + printf " devbox restart : Restart the local development environment based on DevBox container.\n\n" + printf "Arguments\n" + printf " --component -c [Optional] : Specifies the component to restart (e.g., backend, frontend, etc.).\n" + printf " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com endpoint to restart in the DevBox container.\n" + printf " --force -f : Force the restart operation without prompt.\n\n" + printf "Global Arguments\n" + printf " --help -h : Show this help message and exit.\n" + printf "Examples\n" + printf " Restart all components:\n" + printf " devbox restart\n\n" + printf " Restart a specific component (e.g., backend):\n" + printf " devbox restart --component=backend\n" + else + printf "devbox restart - Restart the local development environment based on DevBox container.\n\n" + fi + printf "Alias: r\n" + echo +} + +# :command.normalize_input +# :command.normalize_input_function +normalize_input() { + local arg passthru flags + passthru=false + + while [[ $# -gt 0 ]]; do + arg="$1" + if [[ $passthru == true ]]; then + input+=("$arg") + elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then + input+=("${BASH_REMATCH[1]}") + input+=("${BASH_REMATCH[2]}") + elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then + input+=("${BASH_REMATCH[1]}") + input+=("${BASH_REMATCH[2]}") + elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then + flags="${BASH_REMATCH[1]}" + for ((i = 0; i < ${#flags}; i++)); do + input+=("-${flags:i:1}") + done + elif [[ "$arg" == "--" ]]; then + passthru=true + input+=("$arg") + else + input+=("$arg") + fi + + shift + done +} + +# :command.inspect_args +inspect_args() { + # Check and output the simulated args associative array (using args_keys and args_values) + if [ ${#args_keys[@]} -gt 0 ]; then + # 利用 printf 和 sort 对键进行排序 + sorted_keys=$(printf "%s\n" "${args_keys[@]}" | sort) + echo "args:" + for key in $sorted_keys; do + value="" + # Find the value based on the key + for i in `seq 0 $((${#args_keys[@]} - 1))`; do + if [ "${args_keys[$i]}" = "$key" ]; then + value="${args_values[$i]}" + break + fi + done + + done + else + echo "args: none" + fi + + # Check and output the simulated deps associative array (using deps_keys and deps_values) + if [ ${#deps_keys[@]} -gt 0 ]; then + sorted_keys=$(printf "%s\n" "${deps_keys[@]}" | sort) + echo + echo "deps:" + for key in $sorted_keys; do + value="" + for i in `seq 0 $((${#deps_keys[@]} - 1))`; do + if [ "${deps_keys[$i]}" = "$key" ]; then + value="${deps_values[$i]}" + break + fi + done + echo "- \$deps[$key] = $value" + done + fi + + # Check and output the simulated env_vars associative array (using env_var_names) + if [ ${#env_var_names[@]} -gt 0 ]; then + sorted_names=$(printf "%s\n" "${env_var_names[@]}" | sort) + echo + echo "environment variables:" + for name in $sorted_names; do + # Look up the value based on the name + echo "- \$${name} = ${!name:-}" + done + fi +} + + +install_docker() { + echo "[INFO] Checking Docker installation..." + + # Check if Docker CLI is installed + if ! command -v docker >/dev/null 2>&1; then + echo "[ERROR] Docker CLI is not installed." + return 1 + fi + + echo "[INFO] Docker CLI is installed. Checking daemon..." + + # Check if Docker daemon is running + if docker info >/dev/null 2>&1; then + echo "[OK] Docker daemon is running." + return 0 + fi + + # Check if running on WSL + if grep -qi microsoft /proc/version; then + echo "[INFO] Detected WSL environment. Skipping service startup." + if [ -S /var/run/docker.sock ]; then + echo "[OK] Docker socket found (/var/run/docker.sock)." + return 0 + else + echo "[ERROR] Docker socket /var/run/docker.sock not found." + echo "[SOLUTION] Please start Docker Desktop on Windows and enable WSL integration, then mount /var/run/docker.sock into the container." + return 1 + fi + fi + + # Check if running on macOS + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + echo "[INFO] Running on Linux. Attempting to start Docker service..." + if command -v systemctl >/dev/null 2>&1; then + echo "[INFO] Starting Docker with systemctl..." + sudo systemctl start docker + sleep 2 + if systemctl is-active --quiet docker; then + echo "[OK] Docker service started successfully via systemctl." + return 0 + else + echo "[ERROR] Failed to start Docker using systemctl." + return 1 + fi + elif command -v service >/dev/null 2>&1; then + echo "[INFO] systemctl not found, trying to start Docker using service..." + sudo service docker start + sleep 2 + if docker info >/dev/null 2>&1; then + echo "[OK] Docker service started successfully via service command." + return 0 + else + echo "[ERROR] Failed to start Docker using service command." + return 1 + fi + else + echo "[ERROR] Neither systemctl nor service command found. Please start Docker manually." + return 1 + fi + fi + + return 1 +} + +check_docker_running() { + echo "==> Checking if Docker service is running..." + + # if Docker CLI is installed and Docker daemon is running + if docker info >/dev/null 2>&1; then + echo "==> Docker is running." + return 0 + fi + + # if running on WSL, check for Docker socket + if grep -qi microsoft /proc/version; then + echo "[INFO] Detected WSL environment. Verifying /var/run/docker.sock..." + if [ -S /var/run/docker.sock ]; then + echo "==> Docker socket found. Docker should be available via Docker Desktop." + return 0 + else + echo "[ERROR] Docker socket not found in WSL environment." + return 1 + fi + fi + + echo "==> Docker is not running. Attempting to start it..." + + # Start Docker service using systemctl or service command + if command -v systemctl &>/dev/null; then + if systemctl list-units --type=service | grep -q "docker.service"; then + echo "==> Starting Docker with systemctl..." + sudo systemctl start docker && echo "==> Docker started successfully." && return 0 + fi + fi + + if command -v service &>/dev/null; then + if service --status-all | grep -q "docker"; then + echo "==> Starting Docker with service..." + sudo service docker start && echo "==> Docker started successfully." && return 0 + fi + fi + + if command -v snap &>/dev/null && snap list | grep -q "docker"; then + echo "==> Starting Docker with snap..." + sudo snap start docker && echo "==> Docker started successfully." && return 0 + fi + + echo "ERROR: Unable to start Docker automatically. Please start it manually." + return 1 +} + +# Define the local components and their corresponding ports +local_components_ports_keys=("devsvc" "notification" "content" "central_storage" "authentication") +local_components_ports_values=("8007" "8003" "8013" "8005" "8004") + +# Get the port number for a local component +get_port() { + local comp="$1" + local port="" + for i in "${!local_components_ports_keys[@]}"; do + if [ "${local_components_ports_keys[i]}" = "$comp" ]; then + port="${local_components_ports_values[i]}" + break + fi + done + echo "$port" +} + +# :command.command_functions +# :command.function +devbox_init_command() { + + #!/usr/bin/env bash + echo "==> [INIT] Starting DevBox environment initialization..." + echo + + # ------------------------------------------------------------------- + # 1. Get parameters from command line arguments + # ------------------------------------------------------------------- + local OS="$args_os" # --os + local ARCH="$args_arch" # --arch + local DEVBOX_NAME="$args_devbox_container_name" # --devbox-container-name + local DEVBOX_PORT="$args_devbox_container_port" # --devbox-container-port + local DEVBOX_FRONTEND_PORT="$args_devbox_frontend_port" # --devbox-frontend-port + local DEVBOX_BACKEND_PORT="$args_devbox_backend_port" # --devbox-backend-port + local DEVBOX_REPO="$args_devbox_image_repo" # --devbox-image-repo + local DEVBOX_IMAGE="$args_devbox_image_name" # --devbox-image-name + local DEVBOX_TAG="$args_devbox_image_tag" # --devbox-image-tag + local WORKING_HOME="${args_working_home:-${WORKING_HOME:-${HOME}/devbox}}" + + local FREELEAPS_USERNAME="$args_freeleaps_username" # --freeleaps-username + local FREELEAPS_PASSWORD="$args_freeleaps_password" # --freeleaps-password + + local USE_LOCAL_COMPONENT="$args_use_local_component" # --use-local-component + + local DEVSVC_REPO="$args_devsvc_image_repo" # --devsvc-image-repo + local DEVSVC_IMAGE="$args_devsvc_image_image" # --devsvc-image-image + local DEVSVC_TAG="$args_devsvc_image_tag" # --devsvc-image-tag + + + local CONTENT_REPO="$args_content_image_repo" # --content-image-repo + local CONTENT_IMAGE="$args_content_image_image" # --content-image-image + local CONTENT_TAG="$args_content_image_tag" # --content-image-tag + + local CENTRAL_STORAGE_REPO="$args_central_storage_image_repo" # --central_storage-image-repo + local CENTRAL_STORAGE_IMAGE="$args_central_storage_image_image" # --central_storage-image-image + local CENTRAL_STORAGE_TAG="$args_central_storage_image_tag" # --central_storage-image-tag + + local AUTHENTICATION_REPO="$args_authentication_image_repo" # --authentication-image-repo + local AUTHENTICATION_IMAGE="$args_authentication_image_image" # --authentication-image-image + local AUTHENTICATION_TAG="$args_authentication_image_tag" # --authentication-image-tag + + local NOTIFICATION_REPO="$args_notification_image_repo" # --notification-image-repo + local NOTIFICATION_IMAGE="$args_notification_image_image" # --notification-image-image + local NOTIFICATION_TAG="$args_notification_image_tag" # --notification-image-tag + + local CUSTOM_GIT_REPO="$args_custom_git_repo" # --custom-git-repo + + # --force flag to overwrite existing resources + local FORCE_INIT="${args_force}" + + local OS="$(get_arg '--os')" + local ARCH="$(get_arg '--arch')" + local DEVBOX_NAME="$(get_arg '--devbox-container-name')" + local DEVBOX_PORT="$(get_arg '--devbox-container-port')" + local DEVBOX_FRONTEND_PORT="$(get_arg '--devbox-frontend-port')" + local DEVBOX_BACKEND_PORT="$(get_arg '--devbox-backend-port')" + local DEVBOX_REPO="$(get_arg '--devbox-image-repo')" + local DEVBOX_IMAGE="$(get_arg '--devbox-image-name')" + local DEVBOX_TAG="$(get_arg '--devbox-image-tag')" + local WORKING_HOME="$(get_arg '--working-home' "${WORKING_HOME:-${HOME}/devbox}")" + local FREELEAPS_USERNAME="$(get_arg '--freeleaps-username')" + local FREELEAPS_PASSWORD="$(get_arg '--freeleaps-password')" + local USE_LOCAL_COMPONENT="$(get_arg '--use-local-component')" + local DEVSVC_REPO="$(get_arg '--devsvc-image-repo')" + local DEVSVC_IMAGE="$(get_arg '--devsvc-image-name')" + local DEVSVC_TAG="$(get_arg '--devsvc-image-tag')" + local CONTENT_REPO="$(get_arg '--content-image-repo')" + local CONTENT_IMAGE="$(get_arg '--content-image-name')" + local CONTENT_TAG="$(get_arg '--content-image-tag')" + local CENTRAL_STORAGE_REPO="$(get_arg '--central_storage-image-repo')" + local CENTRAL_STORAGE_IMAGE="$(get_arg '--central_storage-image-name')" + local CENTRAL_STORAGE_TAG="$(get_arg '--central_storage-image-tag')" + local AUTHENTICATION_REPO="$(get_arg '--authentication-image-repo')" + local AUTHENTICATION_IMAGE="$(get_arg '--authentication-image-name')" + local AUTHENTICATION_TAG="$(get_arg '--authentication-image-tag')" + local NOTIFICATION_REPO="$(get_arg '--notification-image-repo')" + local NOTIFICATION_IMAGE="$(get_arg '--notification-image-name')" + local NOTIFICATION_TAG="$(get_arg '--notification-image-tag')" + local CUSTOM_GIT_REPO="$(get_arg '--custom-git-repo')" + + local FORCE_INIT="$(get_arg '--force')" + + local is_pull_all_components=true + local components=("devsvc" "notification" "content" "central_storage" "authentication") + local start_components=() + + # Check if using local components + USE_LOCAL_COMPONENT_VAL=false + if [[ "$(lower "$USE_LOCAL_COMPONENT")" == "true" ]]; then + USE_LOCAL_COMPONENT_VAL=true + fi + + # if use online components, check if any component image repo is specified + if [[ $USE_LOCAL_COMPONENT_VAL == false ]]; then + is_pull_all_components=false + fi + + echo "==> Checking parameters..." + for component in "${components[@]}"; do + if [[ -n "$(get_arg "--${component}-image-repo")" ]]; then + is_pull_all_components=false + start_components+=("${component}") + fi + + # Check ARCH match default component tag value and justify the default Image tag value + if [[ "$ARCH" == "amd64" && "$component" == "devsvc" ]]; then + DEVSVC_TAG="latest-linux-amd64" + elif [[ "$ARCH" == "arm64" && "$component" == "devsvc" ]]; then + DEVSVC_TAG="latest-linux-arm64" + fi + + if [[ "$ARCH" == "amd64" && "$component" == "content" ]]; then + CONTENT_TAG="latest-linux-amd64" + elif [[ "$ARCH" == "arm64" && "$component" == "content" ]]; then + CONTENT_TAG="latest-linux-arm64" + fi + + if [[ "$ARCH" == "amd64" && "$component" == "central_storage" ]]; then + CENTRAL_STORAGE_TAG="latest-linux-amd64" + elif [[ "$ARCH" == "arm64" && "$component" == "central_storage" ]]; then + CENTRAL_STORAGE_TAG="latest-linux-arm64" + fi + + if [[ "$ARCH" == "amd64" && "$component" == "authentication" ]]; then + AUTHENTICATION_TAG="latest-linux-amd64" + elif [[ "$ARCH" == "arm64" && "$component" == "authentication" ]]; then + AUTHENTICATION_TAG="latest-linux-arm64" + fi + + if [[ "$ARCH" == "amd64" && "$component" == "notification" ]]; then + NOTIFICATION_TAG="latest-linux-amd64" + elif [[ "$ARCH" == "arm64" && "$component" == "notification" ]]; then + NOTIFICATION_TAG="latest-linux-arm64" + fi + done + + + # If is_pull_all_components is true, then pull all components + if [[ "$is_pull_all_components" == true ]]; then + start_components=("${components[@]}") + fi + + echo " ===================================================== " + echo "Parameters:" + echo " OS = $OS" + echo " ARCH = $ARCH" + echo " DEVBOX_NAME = $DEVBOX_NAME" + echo " DEVBOX_PORT = $DEVBOX_PORT" + echo " DEVBOX_FRONTEND_PORT = $DEVBOX_FRONTEND_PORT" + echo " DEVBOX_BACKEND_PORT = $DEVBOX_BACKEND_PORT" + echo " DEVBOX_REPO = $DEVBOX_REPO" + echo " DEVBOX_IMAGE = $DEVBOX_IMAGE" + echo " DEVBOX_TAG = $DEVBOX_TAG" + echo " WORKING_HOME = $WORKING_HOME" + echo " FREELEAPS_USERNAME= $FREELEAPS_USERNAME" + echo " (FREELEAPS_PASSWORD is hidden for security)" + echo " USE_LOCAL_COMPONENT= $USE_LOCAL_COMPONENT" + echo " DEVSVC_REPO = $DEVSVC_REPO" + echo " DEVSVC_IMAGE = $DEVSVC_IMAGE" + echo " DEVSVC_TAG = $DEVSVC_TAG" + echo " CONTENT_REPO = $CONTENT_REPO" + echo " CONTENT_IMAGE = $CONTENT_IMAGE" + echo " CONTENT_TAG = $CONTENT_TAG" + echo " CENTRAL_STORAGE_REPO = $CENTRAL_STORAGE_REPO" + echo " CENTRAL_STORAGE_IMAGE= $CENTRAL_STORAGE_IMAGE" + echo " CENTRAL_STORAGE_TAG = $CENTRAL_STORAGE_TAG" + echo " AUTHENTICATION_REPO = $AUTHENTICATION_REPO" + echo " AUTHENTICATION_IMAGE= $AUTHENTICATION_IMAGE" + echo " AUTHENTICATION_TAG = $AUTHENTICATION_TAG" + echo " NOTIFICATION_REPO = $NOTIFICATION_REPO" + echo " NOTIFICATION_IMAGE= $NOTIFICATION_IMAGE" + echo " NOTIFICATION_TAG = $NOTIFICATION_TAG" + echo " FORCE_INIT = $FORCE_INIT" + echo + + # ------------------------------------------------------------------- + # 2. Check OS/ARCH support + # (if using auto, detect current system, here just show simple check) + # ------------------------------------------------------------------- + if [[ "$OS" != "auto" && "$OS" != "linux" && "$OS" != "darwin" && "$OS" != "wsl2" ]]; then + echo "ERROR: Unsupported OS: $OS" + exit 1 + fi + + if [[ "$ARCH" != "auto" && "$ARCH" != "amd64" && "$ARCH" != "arm64" ]]; then + echo "ERROR: Unsupported architecture: $ARCH" + exit 1 + fi + + # Check ARCH match current device + if [[ "$ARCH" == "auto" ]]; then + ARCH="$(uname -m)" + if [[ "$ARCH" == "x86_64" ]]; then + ARCH="amd64" + elif [[ "$ARCH" == "aarch64" ]]; then + ARCH="arm64" + else + echo "ERROR: Unsupported architecture: $ARCH" + exit 1 + fi + fi + + + # Default arch tag value if Arch is amd64 then latest-linux-amd64 else latest-linux-arm64 + local arch_tag="latest-linux-${ARCH}" + + # ------------------------------------------------------------------- + # 3. Check environment requirements + # ------------------------------------------------------------------- + # 3.1 Docker Check + if ! command -v docker &>/dev/null; then + echo "ERROR: docker is not installed or not in PATH." + exit 1 + fi + + # 3.2 Check disk space + local free_space_kb + free_space_kb="$(df -Pk "$HOME" | awk 'END{print $4}')" + # 若无法获取或小于 10GB (10485760 KB),报错 + if [[ -z "$free_space_kb" || $free_space_kb -lt 10485760 ]]; then + echo "ERROR: Insufficient disk space (need >10GB)." + exit 1 + fi + + # 3.3 WORKING_HOME Check + if ! mkdir -p "$WORKING_HOME" 2>/dev/null; then + echo "ERROR: Can't create or write to WORKING_HOME: $WORKING_HOME" + exit 1 + fi + + # 3.4 Network to docker.com(sample:ping docker.com) + if ! ping -c 1 docker.com &>/dev/null; then + echo "ERROR: Network unreachable." + exit 1 + fi + + if [[ -f "$WORKING_HOME/.devbox-instance" && -z "$FORCE_INIT" ]]; then + # Echo all start_components + if [[ "${#start_components[@]}" -gt 0 ]]; then + for component in "${start_components[@]}"; do + if [[ -f "$WORKING_HOME/.${component}-instance" ]]; then + echo "ERROR: Container named $component already exists. Use --force to remove it." + exit 1 + fi + done + else + echo "ERROR: Container named $DEVBOX_NAME already exists. Use --force to remove it." + exit 1 + fi + fi + + # ------------------------------------------------------------------- + # 5.install docker and check docker running + # ------------------------------------------------------------------- + if ! install_docker; then + echo "ERROR: Failed to install Docker or Docker service is not running." + exit 1 + fi + + if ! check_docker_running; then + echo "ERROR: Docker service is not running." + exit 1 + fi + + # ------------------------------------------------------------------- + # 5.1 pull and start DevBox container + # ------------------------------------------------------------------- + local devbox_full_image="${DEVBOX_REPO}/${DEVBOX_IMAGE}:${DEVBOX_TAG}" + echo "==> Pulling DevBox image: $devbox_full_image" + if ! docker pull "$devbox_full_image"; then + echo "ERROR: Failed to pull DevBox image: $devbox_full_image" + exit 1 + fi + + # If container with same name exists, remove it + if docker ps -a --format '{{.Names}}' | grep -q "^${DEVBOX_NAME}\$"; then + if [[ -n "$FORCE_INIT" ]]; then + echo "==> Removing existing container named $DEVBOX_NAME ..." + docker stop "$DEVBOX_NAME" &>/dev/null || true + docker rm "$DEVBOX_NAME" &>/dev/null || true + + # Remove .devbox-instance file + rm -f "$WORKING_HOME/.devbox-instance" + + # Remove .backend.pid .frontend.pid + rm -f "$WORKING_HOME/.backend.pid" + rm -f "$WORKING_HOME/.frontend.pid" + else + echo "ERROR: Container named $DEVBOX_NAME already exists. Use --force to remove it." + exit 1 + fi + fi + + # Create Docker network for DevBox container. TODO: if the network need to be configured in the docker-compose file add some logic to load it from the file + DEVBOX_FREELEAPS2_NETWORK="devbox_freeleaps2-network" + + echo '==> [INIT] Starting DevBox environment initialization...' + # Check if docker network create devbox_freeleaps2-network + if ! docker network ls | grep -q "$DEVBOX_FREELEAPS2_NETWORK"; then + echo "==> Creating Docker network: $DEVBOX_FREELEAPS2_NETWORK" + docker network create "$DEVBOX_FREELEAPS2_NETWORK" + + else + echo "==> Docker network devbox_freeleaps2-network already exists." + fi + + echo '==> [INIT] Starting DevBox container...' + + # Create and start DevBox container + local container_id + container_id="$( + docker run -d \ + --name "$DEVBOX_NAME" \ + -p "${DEVBOX_PORT}:22" \ + -p "${DEVBOX_FRONTEND_PORT}:5173" \ + -p "${DEVBOX_BACKEND_PORT}:8002" \ + -v "$WORKING_HOME:/home/devbox" \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --network "$DEVBOX_FREELEAPS2_NETWORK" \ + "$devbox_full_image" 2>/dev/null + )" + + if [[ -z "$container_id" ]]; then + echo "ERROR: Failed to create DevBox container." + exit 1 + fi + + # record container id, DEVBOX_FRONTEND_PORT, DEVBOX_BACKEND_PORT + echo "$container_id" > "$WORKING_HOME/.devbox-instance" + echo "$DEVBOX_FRONTEND_PORT" > "$WORKING_HOME/.devbox-frontend-port" + echo "$DEVBOX_BACKEND_PORT" > "$WORKING_HOME/.devbox-backend-port" + + # ------------------------------------------------------------------- + # 6. linbwang: pull and start other components + # ------------------------------------------------------------------- + +echo "==> [INIT] Starting Freeleaps services... Use Local component $USE_LOCAL_COMPONENT_VAL" + +export ARCH="$ARCH" +export WORKING_HOME="$WORKING_HOME" +# Check +if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then + + echo ' ===> Using local components for Freeleaps services.' + + export DEVSVC_IMAGE_TAG="$DEVSVC_TAG" + export CONTENT_IMAGE_TAG="$CONTENT_TAG" + export CENTRAL_STORAGE_IMAGE_TAG="$CENTRAL_STORAGE_TAG" + export AUTHENTICATION_IMAGE_TAG="$AUTHENTICATION_TAG" + export NOTIFICATION_IMAGE_TAG="$NOTIFICATION_TAG" + + # Check if gitea_data_backup.tar.gz exists at current script directory, if not exit + if [[ ! -f "gitea_data_backup.tar.gz" ]]; then + echo "ERROR: gitea_data_backup.tar.gz not found. Please make sure it exists in the current directory." + exit 1 + fi + + # Sudo force sudo tar -xzvf gitea_data_backup.tar.gz + sudo tar -xzvf gitea_data_backup.tar.gz + + # Check if data/git, data/gitea, data/ssh directories exist after extracting gitea_data_backup.tar.gz + if [[ ! -d "data/git" || ! -d "data/gitea" || ! -d "data/ssh" ]]; then + echo "ERROR: Failed to extract gitea data backup." + exit 1 + fi + + + + + echo "==> Starting Gitea, MongoDB, RabbitMQ containers..." + # Start local components by docker compose file and start up specified services. docker compose file is in the same directory as the script (docker-compose.dev.arm64.new.yaml) + docker-compose -f docker-compose.dev.arm64.new.yaml up -d mongodb rabbitmq gitea + + sleep 5 + + # start component service from start_components array + docker-compose -f docker-compose.dev.arm64.new.yaml up -d "${start_components[@]}" + + + gitea_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-gitea$" --format "{{.ID}}") + echo "$gitea_container_id" > "$WORKING_HOME/.gitea-instance" + + mongo_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-mongodb$" --format "{{.ID}}") + echo "$mongo_container_id" > "$WORKING_HOME/.mongodb-instance" + + rabbitmq_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-rabbitmq$" --format "{{.ID}}") + echo "$rabbitmq_container_id" > "$WORKING_HOME/.rabbitmq-instance" + + + # Get all components container ids and save to .component-instance file + for component in "${start_components[@]}"; do + tmp_container_id=$(docker ps --no-trunc -a --filter "name=^$component$" --format "{{.ID}}") + echo "$tmp_container_id" > "$WORKING_HOME/.${component}-instance" + done + + echo "${component} container created: $component_container_id" + + # Get the owner group of the WORKING_HOME + if [[ "$(uname)" == "Darwin" ]]; then + OWNER_GROUP=$(stat -f "%Su:%Sg" "${WORKING_HOME}") + else + OWNER_GROUP=$(stat -c "%U:%G" "${WORKING_HOME}") + fi + + # Echo OWNER_GROUP + echo "OWNER_GROUP: $OWNER_GROUP" + + # Copy gitea data to the gitea container + GITEA_HOST_DIR="${WORKING_HOME}/freeleaps2-gitea" + + # Remove existing data directories + sudo rm -rf ${GITEA_HOST_DIR}/git + sudo rm -rf ${GITEA_HOST_DIR}/gitea + sudo rm -rf ${GITEA_HOST_DIR}/ssh + + # Move data directories to the gitea container + sudo mv data/git ${GITEA_HOST_DIR}/ + sudo mv data/gitea ${GITEA_HOST_DIR}/ + sudo mv data/ssh ${GITEA_HOST_DIR}/ + + # Change the owner group of the gitea data directories + sudo chown -R "${OWNER_GROUP}" ${GITEA_HOST_DIR} + echo "Gitea data copying is done" + + # Check if gitea data directories exist in the gitea container + if [[ ! -d "${GITEA_HOST_DIR}/gitea" ]]; then + echo "ERROR: Failed to copy gitea data." + exit 1 + fi + + # restart gitea container + docker-compose -f docker-compose.dev.arm64.new.yaml restart rabbitmq + sleep 10 + + docker-compose -f docker-compose.dev.arm64.new.yaml restart gitea + sleep 5 + + # restart notification if it is in the start_components + if [[ " ${start_components[@]} " =~ "notification" ]]; then + docker-compose -f docker-compose.dev.arm64.new.yaml restart notification + fi +else + echo '============================================' + echo ' ===> Using online components for Freeleaps services.' + echo '============================================' + # Start Gitea, MongoDB, RabbitMQ containers + docker-compose -f docker-compose.dev.arm64.new.yaml up -d mongodb rabbitmq + echo "===> start components is $start_components" + + # Save MongoDB and RabbitMQ container ids to .mongodb-instance and .rabbitmq-instance + mongo_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-mongodb\$") + echo "$mongo_container_id" > "$WORKING_HOME/.mongodb-instance" + + rabbitmq_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-rabbitmq\$") + echo "$rabbitmq_container_id" > "$WORKING_HOME/.rabbitmq-instance" +fi + +# Check all components are started +for component in "${start_components[@]}"; do + if [[ -z "$(docker ps -a --format '{{.Names}}' | grep "^$component\$")" ]]; then + echo "ERROR: Failed to start $component container." + exit 1 + fi +done + + +# Save $USE_LOCAL_COMPONENT false/true to $WORKING_HOME/.use-local-component +echo "$USE_LOCAL_COMPONENT" > "$WORKING_HOME/.use-local-component" + +pushd $WORKING_HOME + + +IS_START_FRONTEND=false + +# Make a user input (Y/N) to continue pull freeleaps.com code and start if N then exit +read -p "Do you want to continue to pull freeleaps.com code and start the services? (Y/N): " user_input +if [[ "$user_input" == "N" || "$user_input" == "n" ]]; then + # Echo as init job completed and exit + echo + echo "===========================================================" + echo "DevBox init completed successfully!" + echo "DevBox Environment Details:" + echo " DevBox container name: $DEVBOX_NAME" + echo " DevBox container ID: $WORKING_HOME/.devbox-instance" + echo "===========================================================" + echo + exit 0 +fi + +IS_START_FRONTEND=true + +# Check if username and password are set +if [[ -z "$FREELEAPS_USERNAME" || -z "$FREELEAPS_PASSWORD" ]]; then + echo "Warining: Username and password are required to pull freeleaps.com code." + echo "==> [INIT] DevBox environment initialization completed." + exit 1 +fi + +# Test if the user can access the freeleaps.com repository +echo "==> Testing access to freeleaps.com repository..." +if ! git ls-remote "https://$FREELEAPS_USERNAME:$FREELEAPS_PASSWORD@freeleaps.com:3443/products/freeleaps.git" &>/dev/null; then + echo "ERROR: Failed to access freeleaps.com repository. Please check your username and password." + echo "==> [INIT] DevBox environment initialization completed successfully, but access to the freeleaps.com repository failed." + exit 1 +fi + +FRONTEND_GIT_URL="https://$FREELEAPS_USERNAME:$FREELEAPS_PASSWORD@freeleaps.com:3443/products/freeleaps.git" +# Check if freeleaps2-frontend exists, if not git clone it +if [ ! -d $WORKING_HOME/freeleaps ]; then + echo "Git cloning freeleaps.com:3443/products/freeleaps.git" + git clone --depth 5 $FRONTEND_GIT_URL +else + pushd $WORKING_HOME/freeleaps + # Check $WORKING_HOME/freeleaps exists and it is a git repository, if not git clone it + if ! git rev-parse --is-inside-work-tree &>/dev/null; then + echo "Git cloning freeleaps.com:3443/products/freeleaps.git" + git clone --depth 5 $FRONTEND_GIT_URL + else + echo "Git pulling freeleaps.com:3443/products/freeleaps.git" + git pull + fi +fi + + +# Run banckend service and frontend service in the container +docker exec -i "$DEVBOX_NAME" bash < Using local components" + # Local components for Freeleaps services (devsvc, notification, content, central_storage, authentication) + cat << 'EOFinner' > /home/devbox/freeleaps/apps/.env + # Online endpoint info + export MONGODB_NAME=freeleaps2 + export MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ + export MONGODB_PORT=27017 + export BLOB_STORE_CONNECTION_STR="DefaultEndpointsProtocol=https;AccountName=freeleaps1static;AccountKey=SIk7S3RviJxl1XhGiDZKA3cvzfxNrSbsBMfJ3EbKTsKPeMwhy8FTLpJliRLzQVE6uaSX8giDYw2h+ASt5MmHxQ==;EndpointSuffix=core.windows.net" + export RABBITMQ_HOSTNAME=freeleaps2 + export RABBITMQ_HOST=freeleaps2-rabbitmq + export RABBITMQ_PORT=5672 + export FREELEAPS_ENV=dev + export STRIPE_API_KEY=sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd + export STRIPE_WEBHOOK_SECRET=whsec_S6ZWjSAdR5Cpsn2USH6ZRBqbdBIENjTC + export STRIPE_ACCOUNT_WEBHOOK_SECRET=whsec_PgPnkWGhEUiQfnV8aIb5Wmruz7XETJLm + export SITE_URL_ROOT=http://localhost + export FREELEAPS_DEVSVC_ENDPOINT=http://devsvc:8007/api/devsvc/ + export FREELEAPS_CHAT_ENDPOINT=http://freeleaps-chat:8012/api/chat/ + export FREELEAPS_CONTENT_ENDPOINT=http://content:8013/api/content/ + export FREELEAPS_NOTIFICATION_ENDPOINT=http://notification:8003/api/notification/ + export FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://central_storage:8005/api/central_storage/ + export FREELEAPS_AUTHENTICATION_ENDPOINT=http://authentication:8004/api/auth/ + export FREELEAPS_AILAB_ENDPOINT=https://localhost:8009/api/ + export KAFKA_SERVER_URL='' + export JWT_SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b + export EMAIL_FROM=freeleaps@freeleaps.com +EOFinner +else + echo "==> Using online components" + cat << 'EOFinner' > /home/devbox/freeleaps/apps/.env + # Online endpoint info + export MONGODB_NAME=freeleaps2 + export MONGODB_PORT=27017 + export MONGODB_URI='mongodb+srv://jetli:8IHKx6dZK8BfugGp@freeleaps2.hanbj.mongodb.net/' + export RABBITMQ_HOSTNAME=freeleaps2 + export RABBITMQ_HOST=52.149.35.244 + export RABBITMQ_PORT=5672 + export FREELEAPS_ENV=dev + export STRIPE_API_KEY=sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd + export STRIPE_WEBHOOK_SECRET=whsec_S6ZWjSAdR5Cpsn2USH6ZRBqbdBIENjTC + export STRIPE_ACCOUNT_WEBHOOK_SECRET=whsec_PgPnkWGhEUiQfnV8aIb5Wmruz7XETJLm + export SITE_URL_ROOT=http://localhost/ + export FREELEAPS_DEVSVC_ENDPOINT=http://52.149.3.85:8007/api/devsvc/ + export FREELEAPS_CHAT_ENDPOINT=https://freeleaps-alpha.com/api/chat/ + export FREELEAPS_CONTENT_ENDPOINT=http://52.149.35.244:8013/api/content/ + export FREELEAPS_NOTIFICATION_ENDPOINT=http://52.149.35.244:8003/api/notification/ + export FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://52.149.35.244:8005/api/central_storage/ + export FREELEAPS_AUTHENTICATION_ENDPOINT=http://52.149.35.244:8004/api/auth/ + export FREELEAPS_AILAB_ENDPOINT=https://as010-w2-re-vm.mathmast.com:8009/api/ + export KAFKA_SERVER_URL='' + export EMAIL_FROM=freeleaps@freeleaps.com + export JWT_SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0 +EOFinner +fi + +# Effect the environment variables in the current shell + +source /home/devbox/freeleaps/apps/.env + +# Ensure /home/devbox/logs exists +mkdir -p /home/devbox/logs + +# Start WebAPI service +echo "Starting WebAPI service..." +pushd /home/devbox/freeleaps/apps +cp /home/devbox/freeleaps/backend_env.sh /home/devbox/freeleaps/apps/backend_env.sh + +# 5. Istall python3.10 and venv module +echo "5. Istall python3.10 and venv module" +sudo apt update +sudo apt install python3.10 python3.10-venv -y + +# make sore python3.10 is installed +if ! command -v python3.10 &>/dev/null; then + echo "ERROR: Python3.10 is not installed." + exit 1 +fi + +# Upgrade pip and install virtualenv +echo "7. Upgrade pip and install virtualenv" +python3.10 -m ensurepip --upgrade +python3.10 -m pip install --upgrade pip + +# 8. Create and activate a virtual environment +echo "8. Create and activate a virtual environment" +python3.10 -m venv venv_t + +sleep 5 + +# CHeck if the virtual environment is created +if [ ! -f "venv_t/bin/activate" ]; then + echo "ERROR: The virtual environment cannot be created" + exit 1 +fi + +echo '============================================' +echo ' Start to activate virtual environment' +echo '============================================' +source venv_t/bin/activate +source /home/devbox/freeleaps/apps/.env + +# Verify the virtual environment is activated +if [[ "\$VIRTUAL_ENV" != "" ]]; then + echo "Virtual environment activate: \$VIRTUAL_ENV" +else + echo "ERROR: The virtual environment cannot be startup \$VIRTUAL_ENV" + exit 1 +fi + + +echo '============================================' +echo ' Install requirements' +echo '============================================' +pip install -r /home/devbox/freeleaps/apps/requirements.txt + + + +echo '============================================' +echo 'Start to run start_webapi.sh' +echo '============================================' +./start_webapi.sh > /home/devbox/logs/backend.logs 2>&1 & +BACKEND_PID=\$! + +# Save BACKEND_PID to a file \${WORKING_HOME}/.backend.pid: Stores the process id of backend process. +echo "\$BACKEND_PID" > /home/devbox/.backend.pid + +echo '============================================' +echo 'Check if the WebAPI service started successfully' +echo '============================================' + +sleep 30 + +# 30 attempts, 5 seconds each, total wait time 2.5 minutes +MAX_ATTEMPTS=30 +ATTEMPT=0 + +echo "Waiting for WebAPI service to become healthy..." + +while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do + HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$DEVBOX_BACKEND_PORT/docs") + # Check HTTP Code 200 + if [ "\$HTTP_CODE" -eq 200 ]; then + echo "Backend Swagger UI is available at \$URL (HTTP \$HTTP_CODE)" + break + else + echo "Waiting for Swagger UI to become available... Attempt \$((ATTEMPT+1))" + ATTEMPT=\$((ATTEMPT+1)) + sleep 5 # Wait 5 seconds + fi +done + +if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then + echo "ERROR: WebAPI failed to start after \$MAX_ATTEMPTS attempts" + exit 1 +fi + + +echo '============================================' +echo ' Start frontend service locally' +echo '============================================' +pushd /home/devbox/freeleaps/frontend + +# start the frontend service +export VITE_API_URL='http://127.0.0.1:8002' +export VITE_WEBSOCKET_URL='http://127.0.0.1:8002' + +if [[ \$USE_LOCAL_COMPONENT_VAL == true ]]; then + export VITE_PROXY_WEBSOCKET_CHAT_URL='ws://localhost:8012' + export VITE_PROXY_API_CHAT_URL='http://localhost:8012' +else + export VITE_PROXY_WEBSOCKET_CHAT_URL='wss://freeleaps-alpha.com' + export VITE_PROXY_API_CHAT_URL='https://freeleaps-alpha.com' +fi + + +npm update + +# 1️⃣ Install pnpm globally +npm install -g pnpm + +# 2️⃣ Verify installation +pnpm --version + +# 3️⃣ Clean up old dependencies +rm -rf node_modules pnpm-lock.yaml + +# 4️⃣ Install dependencies (ensuring lockfile updates) +pnpm install --no-frozen-lockfile + +# 5️⃣ Build the project +npm run build + +# 6️⃣ Format the code (Optional) +npm run format +# Start the frontend service with nohup in order to keep it running after the SSH session is closed. Save the process ID of the frontend service +nohup npm run dev > /home/devbox/logs/frontend.logs 2>&1 & +FRONTEND_PID=\$! + +echo "npm run dev has been started with PID: \$FRONTEND_PID" +echo "\$FRONTEND_PID" > /home/devbox/.frontend.pid + + +echo '============================================' + +# Wait for the frontend service to start +sleep 30 + +# 30 attempts, 10 seconds each, total wait time 5 minutes +MAX_ATTEMPTS=30 +ATTEMPT=0 + +echo "Waiting for Frontend service to start..." + +while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do + HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$DEVBOX_FRONTEND_PORT/") + # Check HTTP Code 200 + if [ "\$HTTP_CODE" -eq 200 ]; then + echo "Frontend is available (HTTP \$HTTP_CODE)" + break + else + echo "Waiting for Frontend to become available... (http://localhost:\$DEVBOX_FRONTEND_PORT), (HTTP \$HTTP_CODE) Attempt \$((ATTEMPT+1))" + ATTEMPT=\$((ATTEMPT+1)) + sleep 10 + fi +done + +if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then + echo "ERROR: Frontend failed to start after \$MAX_ATTEMPTS attempts" + exit 1 +fi + + +echo "Freeleaps services started successfully" +EOF + + + + # ------------------------------------------------------------------- + # 10. Final notification + # ------------------------------------------------------------------- + echo + echo "===========================================================" + echo "DevBox init completed successfully!" + echo "DevBox Environment Details:" + echo "1. Code repository is located at: ${WORKING_HOME}/freeleaps" + echo "2. Open up the frontend by visiting: http://localhost:${DEVBOX_FRONTEND_PORT}" + echo "3. Log files can be viewed at:" + echo " - Backend logs: ${WORKING_HOME}/logs/backend.logs" + echo " - Frontend logs: ${WORKING_HOME}/logs/frontend.logs" + echo " DevBox container ID: $WORKING_HOME/.devbox-instance" + echo " Backend PID: $WORKING_HOME/.backend.pid" + echo " Frontend PID: $WORKING_HOME/.frontend.pid" + echo "===========================================================" + echo + +} + + +# :command.function +devbox_deinit_command() { + + # src/deinit_command.sh + echo "# It contains the implementation for the 'devbox deinit' command." + local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" + local CLEAR_LOGS="$(get_arg '--clear-logs')" + local CLEAR_REPO="$(get_arg '--clear-repo')" + + local FORCE="$(get_arg '--force')" + + # print the parameters + echo "==> Deinitialization parameters:" + echo " WORKING_HOME = $WORKING_HOME" + echo " CLEAR_LOGS = $CLEAR_LOGS" + echo " CLEAR_REPO = $CLEAR_REPO" + echo " FORCE = $FORCE" + + echo "==> Starting DevBox deinitialization..." + + # Stop and remove DevBox container + if [[ -f "$WORKING_HOME/.devbox-instance" ]]; then + local container_id + container_id=$(cat "$WORKING_HOME/.devbox-instance") + echo "==> Stopping and removing DevBox container: $container_id" + docker stop "$container_id" &>/dev/null || true + docker rm "$container_id" &>/dev/null || true + rm -f "$WORKING_HOME/.devbox-instance" + + # Remove the frontend and backend ports if the file exists + rm -f "$WORKING_HOME/.devbox-frontend-port" + rm -f "$WORKING_HOME/.devbox-backend-port" + + # Remove the backend and frontend process IDs + rm -f "$WORKING_HOME/.backend.pid" + rm -f "$WORKING_HOME/.frontend.pid" + fi + + if [[ -f "$WORKING_HOME/.gitea-instance" ]]; then + local gitea_container_id + gitea_container_id=$(cat "$WORKING_HOME/.gitea-instance") + echo "==> Stopping and removing Gitea container: $gitea_container_id" + docker stop "$gitea_container_id" &>/dev/null || true + docker rm "$gitea_container_id" &>/dev/null || true + rm -f "$WORKING_HOME/.gitea-instance" + fi + + # Stop and remove MongoDB container + if [[ -f "$WORKING_HOME/.mongodb-instance" ]]; then + local mongodb_container_id + mongodb_container_id=$(cat "$WORKING_HOME/.mongodb-instance") + echo "==> Stopping and removing MongoDB container: $mongodb_container_id" + docker stop "$mongodb_container_id" &>/dev/null || true + docker rm "$mongodb_container_id" &>/dev/null || true + rm -f "$WORKING_HOME/.mongodb-instance" + fi + + # Stop and remove RabbitMQ container + if [[ -f "$WORKING_HOME/.rabbitmq-instance" ]]; then + local rabbitmq_container_id + rabbitmq_container_id=$(cat "$WORKING_HOME/.rabbitmq-instance") + echo "==> Stopping and removing RabbitMQ container: $rabbitmq_container_id" + docker stop "$rabbitmq_container_id" &>/dev/null || true + docker rm "$rabbitmq_container_id" &>/dev/null || true + rm -f "$WORKING_HOME/.rabbitmq-instance" + fi + + # Stop and remove other components + local components=("devsvc" "notification" "content" "central_storage" "authentication") + for component in "${components[@]}"; do + if [[ -f "$WORKING_HOME/.${component}-instance" ]]; then + local component_container_id + component_container_id=$(cat "$WORKING_HOME/.${component}-instance") + echo "==> Stopping and removing ${component} container: $component_container_id" + docker stop "$component_container_id" &>/dev/null || true + docker rm "$component_container_id" &>/dev/null || true + rm -f "$WORKING_HOME/.${component}-instance" + fi + done + + + # Clear the DevBox container logs + if [[ "$CLEAR_LOGS" == "true" ]]; then + echo "==> Clearing logs in $WORKING_HOME/logs..." + if [[ -d "$WORKING_HOME/logs" ]]; then + sudo chown -R $(whoami):$(whoami) "$WORKING_HOME/logs" + rm -rf "$WORKING_HOME/logs" 2>/dev/null || true + mkdir -p "$WORKING_HOME/logs" 2>/dev/null || true + fi + else + echo "==> Skipping log clearing." + fi + + # Clear the source repository + if [[ "$CLEAR_REPO" == "true" && -d "$WORKING_HOME/freeleaps" ]]; then + echo "==> Deleting source repository at $WORKING_HOME/freeleaps" + sudo chown -R $(whoami):$(whoami) "$WORKING_HOME/freeleaps" + rm -rf "$WORKING_HOME/freeleaps" 2>/dev/null || true + rmdir "$WORKING_HOME/freeleaps" 2>/dev/null || true + else + echo "==> Skipping repository deletion." + fi + + if [[ "$CLEAR_LOGS" == "true" ]]; then + # Check if logs directory is removed + if [[ -d "$WORKING_HOME/logs" ]]; then + echo "[WARNING] $WORKING_HOME/logs still exists after removal." + rm -rf "$WORKING_HOME/logs" + else + echo "==> Logs directory removed successfully." + fi + fi + + # Sleep 5 seconds to allow the services to stop, for each second echo 5 seconds increase from 1 to 5 in each second by - + for i in {1..5}; do + echo -n "=" + sleep 1 + done + + # Remove the use-local-component file + rm -f "$WORKING_HOME/.use-local-component" + + echo "> DevBox deinitialization completed." +} + +# :command.function +devbox_start_command() { + + local COMPONENT="$(get_arg '--component')" + local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" + local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')" + + # Check if the DevBox container is running + local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance" + if [[ ! -f "$devbox_container_id_file_path" ]]; then + echo "ERROR: DevBox container is not running. Please run 'devbox init' first." + exit 1 + fi + + local devbox_container_id=$(cat "$devbox_container_id_file_path") + + # Check if use local component + if [[ -f "$WORKING_HOME/.use-local-component" ]]; then + USE_LOCAL_COMPONENT=$(cat "$WORKING_HOME/.use-local-component") + else + USE_LOCAL_COMPONENT="false" + fi + + if [[ "$(lower "$USE_LOCAL_COMPONENT")" == "true" ]]; then + echo "==> Using local components for Freeleaps services." + USE_LOCAL_COMPONENT="true" + else + echo "==> Using online components for Freeleaps services." + USE_LOCAL_COMPONENT="false" + fi + + if [[ "$USE_LOCAL_COMPONENT" == "true" ]]; then + # If no component is specified, start all components + if [[ -z "$COMPONENT" ]]; then + COMPONENTS=( "gitea" "mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") + else + COMPONENTS=("$COMPONENT") + fi + else + # If no component is specified, start all components + if [[ -z "$COMPONENT" ]]; then + COMPONENTS=("mongodb" "rabbitmq" "devbox") + else + if [[ "$COMPONENT" == "devsvc" || "$COMPONENT" == "notification" || "$COMPONENT" == "content" || "$COMPONENT" == "central_storage" || "$COMPONENT" == "authentication" ]]; then + echo "ERROR: Remote component $COMPONENT cannot be restarted." + exit 1 + fi + + COMPONENTS=("$COMPONENT") + fi + fi + + + # Start the specified components + for comp in "${COMPONENTS[@]}"; do + case "$comp" in + "gitea" | "mongodb" | "rabbitmq" | "devbox" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") + echo "==> Starting $comp service..." + # Check if the component container file exists + local component_container_id_file_path="${WORKING_HOME}/.${comp}-instance" + if [[ ! -f "$component_container_id_file_path" ]]; then + echo "ERROR: $comp container is not running. Please run 'devbox init' first." + else + local component_container_id=$(cat "$component_container_id_file_path") + if ! docker ps --no-trunc --format '{{.ID}}' | grep -q "^${component_container_id}\$"; then + echo "==> $comp container is not running, starting container..." + # Start the container + if ! docker start "${component_container_id}"; then + echo "ERROR: Failed to start $comp container." + else + echo "==> $comp container started successfully." + fi + else + echo "==> $comp container is already running." + fi + fi + ;; + *) + echo "ERROR: Unknown component: $comp" + exit 1 + ;; + esac + done + + + + if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then + # Sleep for 10 seconds to allow the services to start and echo 10 seconds increase from 1 to 10 in each second + for i in {1..20}; do + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then + break + fi + echo -n "-" + sleep 1 + done + + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then + echo "==> Starting Freeleaps frontend and backend services..." + # Start the backend and frontend services + docker exec -i "$devbox_container_id" bash < /home/devbox/logs/backend.logs 2>&1 & +BACKEND_PID=\$! + +# Save BACKEND_PID to a file \${WORKING_HOME}/.backend.pid: Stores the process id of backend process. +echo "\$BACKEND_PID" > /home/devbox/.backend.pid + +# Check if the backend service started successfully +sleep 10 +if ! ps -p "\$BACKEND_PID" &>/dev/null; then + echo "ERROR: Backend service failed to start." + exit 1 +fi + +# Test backend and frontend services +echo "Testing backend and frontend services..." + +# Test the backend service +echo "Testing backend service..." +attempt=0 +max_attempts=10 +while [ \$attempt -lt \$max_attempts ]; do + http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs") + if [ "\$http_code" -eq 200 ]; then + break + fi + attempt=\$((attempt+1)) + sleep 5 +done + +if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Backend service is not available after \$max_attempts attempts." + exit 1 +fi + + +# Start the frontend service + +echo '============================================' +echo ' Start frontend service locally' +echo '============================================' +pushd /home/devbox/freeleaps/frontend + +npm run dev > /home/devbox/logs/frontend.logs 2>&1 & +FRONTEND_PID=\$! + +echo "\$FRONTEND_PID" > /home/devbox/.frontend.pid + +# Check if the frontend service started successfully +sleep 10 +if ! ps -p "\$FRONTEND_PID" &>/dev/null; then + echo "ERROR: Frontend service failed to start." + exit 1 +fi + + +# Test the frontend service + +WEB_APP_ACCESS_PORT=\$(cat /home/devbox/.devbox-frontend-port) + +echo "Testing frontend service... PORT: \$WEB_APP_ACCESS_PORT" +attempt=0 +max_attempts=10 +while [ \$attempt -lt \$max_attempts ]; do + HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$WEB_APP_ACCESS_PORT/") + # Check HTTP Code 200 + if [ "\$HTTP_CODE" -eq 200 ]; then + echo "Frontend is available (HTTP \$HTTP_CODE)" + break + else + echo "Attempt \$((attempt+1)): Frontend not available (HTTP \$HTTP_CODE). Waiting..." + attempt=\$((attempt+1)) + sleep 10 + fi +done + +if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Frontend service is not available after \$max_attempts attempts." + exit 1 +fi + +echo "Backend and frontend services started successfully." +EOF + else + echo "ERROR: DevBox container is not running." + exit 1 + fi +fi + + + + + echo "==> DevBox services started successfully." +} + +# :command.function +devbox_stop_command() { + echo "==> Stopping DevBox services..." + local COMPONENT="$(get_arg '--component')" + local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" + + # If the DevBox container is not running, exit + if [[ -z "$COMPONENT" ]]; then + COMPONENTS=("gitea" "mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") + else + COMPONENTS=("$COMPONENT") + fi + + # Stop the specified components + for comp in "${COMPONENTS[@]}"; do + case "$comp" in + "devbox") + if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.devbox-instance") + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then + echo "==> Stopping devbox..." + docker stop "$container_id" &>/dev/null || true + # Remove the frontend and backend pid files + rm -f "${WORKING_HOME}/.backend.pid" + rm -f "${WORKING_HOME}/.frontend.pid" + else + echo "==> DevBox container is not running." + fi + else + echo "==> Backend service is not running." + fi + ;; + + "gitea"| "mongodb"| "rabbitmq" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") + if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.${comp}-instance") + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then + echo "==> Stopping $comp service..." + docker stop "$container_id" &>/dev/null || true + else + echo "==> $comp service is not running." + fi + else + echo "==> $comp service is not running." + fi + ;; + *) + echo "ERROR: Unknown component: $comp" + exit 1 + ;; + esac + done + echo "==> All conponent services stopped successfully." +} + +# :command.function +devbox_status_command() { + + echo "==> Checking DevBox services status..." + local COMPONENT="$(get_arg '--component')" + local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" + + # Check if .devbox-instance file exists + if [[ ! -f "${WORKING_HOME}/.devbox-instance" ]]; then + echo "==> DevBox container is not running." + exit 1 + fi + + local devbox_container_id=$(cat "${WORKING_HOME}/.devbox-instance") + + # If the DevBox container devbox_container_id is not running, exit + if ! docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then + echo "==> DevBox container is not running." + exit 1 + fi + + # If no component is specified, check all components + if [[ -z "$COMPONENT" ]]; then + COMPONENTS=("mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") + else + COMPONENTS=("$COMPONENT") + fi + + # Check the status of the specified components + for comp in "${COMPONENTS[@]}"; do + case "$comp" in + "mongodb") + echo "==> Checking MongoDB status..." + if [[ -f "${WORKING_HOME}/.mongodb-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.mongodb-instance") + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then + echo "[RESULT]: MongoDB container is running." + else + echo "[RESULT]: MongoDB container is not running." + fi + else + echo "[RESULT]: MongoDB container is not running." + fi + ;; + + "rabbitmq") + echo "==> Checking RabbitMQ status..." + if [[ -f "${WORKING_HOME}/.rabbitmq-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.rabbitmq-instance") + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then + echo "[RESULT]: RabbitMQ container is running." + else + echo "[RESULT]: RabbitMQ container is not running." + fi + else + echo "[RESULT]: RabbitMQ container is not running." + fi + ;; + + "devbox") + echo "==> Checking devbox service status..." + if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.devbox-instance") + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then + echo "[RESULT]: devbox container is running." + else + echo "[RESULT]: devbox container is not running." + fi + else + echo "[RESULT]: devbox container is not running." + fi + ;; + + "devsvc" | "notification" | "content" | "central_storage" | "authentication") + echo "==> Checking $comp service status..." + if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.${comp}-instance") + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then + echo "[RESULT]: $comp service is running." + else + echo "[RESULT]: $comp service is not running." + fi + else + echo "[RESULT]: $comp service is not running." + fi + ;; + + *) + echo "ERROR: Unknown component: $comp" + exit 1 + ;; + esac + done + echo "==> DevBox services status checked successfully." +} + +# :command.function +devbox_restart_command() { + echo "==> Restarting DevBox services..." + local COMPONENT="$(get_arg '--component')" + local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" + local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')" + + # Check devbox container file path + local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance" + if [[ ! -f "$devbox_container_id_file_path" ]]; then + echo "ERROR: DevBox container is not running. Please run 'devbox init' first." + exit 1 + fi + + local devbox_container_id=$(cat "$devbox_container_id_file_path") + + # Check if current environment is using local components + USE_LOCAL_COMPONENT=$(cat "${WORKING_HOME}/.use-local-component" 2>/dev/null || true) + if [[ "$USE_LOCAL_COMPONENT" == "true" ]]; then + echo "==> Using local components..." + if [[ -z "$COMPONENT" ]]; then + COMPONENTS=("gitea" "mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") + else + COMPONENTS=("$COMPONENT") + fi + else + echo "==> Using remote components..." + if [[ -z "$COMPONENT" ]]; then + COMPONENTS=("mongodb" "rabbitmq" "devbox") + else + if [[ "$COMPONENT" == "devsvc" || "$COMPONENT" == "notification" || "$COMPONENT" == "content" || "$COMPONENT" == "central_storage" || "$COMPONENT" == "authentication" ]]; then + echo "ERROR: Remote component $COMPONENT cannot be restarted." + exit 1 + fi + + COMPONENTS=("$COMPONENT") + fi + fi + + # Stop the specified components + for comp in "${COMPONENTS[@]}"; do + case "$comp" in + "devbox") + if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.devbox-instance") + echo "==> Stopping devbox service..." + docker stop "$container_id" &>/dev/null || true + + # Remove the frontend and backend pid files + rm -f "${WORKING_HOME}/.backend.pid" + rm -f "${WORKING_HOME}/.frontend.pid" + else + echo "==> Devbox is not running." + fi + ;; + + "gitea" | "mongodb" | "rabbitmq" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") + + if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.${comp}-instance") + echo "==> Stopping $comp service..." + docker stop "$container_id" &>/dev/null || true + else + echo "==> $comp service is not running." + fi + ;; + *) + echo "ERROR: Unknown component: $comp" + exit 1 + ;; + esac + done + + # Start the specified components + for comp in "${COMPONENTS[@]}"; do + case "$comp" in + "gitea" | "mongodb" | "rabbitmq" | "devbox" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") + echo "==> Restarting $comp service..." + if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then + local container_id + container_id=$(cat "${WORKING_HOME}/.${comp}-instance") + docker start "$container_id" &>/dev/null || true + else + echo "==> $comp service is not running." + fi + ;; + *) + echo "ERROR: Unknown component: $comp" + exit 1 + ;; + esac + done + +if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then + # Sleep for 10 seconds to allow the services to start and echo 10 seconds increase from 1 to 10 in each second + for i in {1..20}; do + if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then + break + fi + echo -n "-" + sleep 1 + done + # Start the backend and frontend services + docker exec -i "$devbox_container_id" bash < /home/devbox/logs/backend.logs 2>&1 & +BACKEND_PID=\$! + +# Save BACKEND_PID to a file \${WORKING_HOME}/.backend.pid: Stores the process id of backend process. +echo "\$BACKEND_PID" > /home/devbox/.backend.pid + +# Check if the backend service started successfully +sleep 10 +if ! ps -p "\$BACKEND_PID" &>/dev/null; then + echo "ERROR: Backend service failed to start." + exit 1 +fi + +# Test backend and frontend services +echo "Testing backend and frontend services..." + +# Test the backend service +echo "Testing backend service..." +attempt=0 +max_attempts=10 +while [ \$attempt -lt \$max_attempts ]; do + http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs") + if [ "\$http_code" -eq 200 ]; then + break + fi + attempt=\$((attempt+1)) + sleep 5 +done + +if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Backend service is not available after \$max_attempts attempts." + exit 1 +fi + + +# Start the frontend service + +echo '============================================' +echo ' Start frontend service locally' +echo '============================================' +pushd /home/devbox/freeleaps/frontend + +npm run dev > /home/devbox/logs/frontend.logs 2>&1 & +FRONTEND_PID=\$! + +echo "\$FRONTEND_PID" > /home/devbox/.frontend.pid + +# Check if the frontend service started successfully +sleep 10 +if ! ps -p "\$FRONTEND_PID" &>/dev/null; then + echo "ERROR: Frontend service failed to start." + exit 1 +fi + + +# Test the frontend service +WEB_APP_ACCESS_PORT=\$(cat /home/devbox/.devbox-frontend-port) + +echo "Testing frontend service..." +attempt=0 +max_attempts=10 +while [ \$attempt -lt \$max_attempts ]; do + http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$WEB_APP_ACCESS_PORT/") + if [ "\$http_code" -eq 200 ]; then + echo "Frontend service is available (HTTP \$http_code)" + break + else + echo "Attempt \$((attempt+1)): Frontend not available (HTTP \$http_code). Waiting..." + attempt=\$((attempt+1)) + sleep 10 + fi +done + +if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Frontend service is not available after \$max_attempts attempts." + exit 1 +fi + +echo "Backend and frontend services started successfully." +EOF + fi + + echo "==> DevBox services restarted successfully." +} + +# :command.parse_requirements +parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --version | -v) + version_command + exit + ;; + + --help | -h) + long_usage=yes + devbox_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.environment_variables_filter + + env_var_names+=("FREELEAPS_USERNAME") + env_var_names+=("FREELEAPS_PASSWORD") + env_var_names+=("WORKING_HOME") + + # :command.command_filter + action=${1:-} + + case $action in + -*) ;; + + init | i) + action="init" + shift + devbox_init_parse_requirements "$@" + shift $# + ;; + + deinit | d) + action="deinit" + shift + devbox_deinit_parse_requirements "$@" + shift $# + ;; + + start | s) + action="start" + shift + devbox_start_parse_requirements "$@" + shift $# + ;; + + stop | p) + action="stop" + shift + devbox_stop_parse_requirements "$@" + shift $# + ;; + + status | t) + action="status" + shift + devbox_status_parse_requirements "$@" + shift $# + ;; + + restart | r) + action="restart" + shift + devbox_restart_parse_requirements "$@" + shift $# + ;; + + # :command.command_fallback + "") + devbox_usage >&2 + exit 1 + ;; + + *) + printf "invalid command: %s\n" "$action" >&2 + exit 1 + ;; + + esac + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + +} + + +# :command.parse_requirements +devbox_init_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --help | -h) + long_usage=yes + devbox_init_usage + exit + ;; + *) + break + ;; + esac + done + + # :command.command_filter + action="init" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --os | -o) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--os' "$2" + shift 2 + else + printf "%s\n" "--os requires an argument: --os OS" >&2 + exit 1 + fi + ;; + # :flag.case + --arch | -a) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--arch' "$2" + shift 2 + else + printf "%s\n" "--arch requires an argument: --arch ARCH" >&2 + exit 1 + fi + ;; + # :flag.case + --devbox-container-name | -N) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-container-name' "$2" + shift 2 + else + printf "%s\n" "--devbox-container-name requires an argument: --devbox-container-name DEVBOX_CONTAINER_NAME" >&2 + exit 1 + fi + ;; + # :flag.case + --devbox-container-port | -P) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-container-port' "$2" + shift 2 + else + printf "%s\n" "--devbox-container-port requires an argument: --devbox-container-port DEVBOX_CONTAINER_PORT" >&2 + exit 1 + fi + ;; + --devbox-frontend-port | -F) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-frontend-port' "$2" + shift 2 + else + printf "%s\n" "--devbox-frontend-port requires an argument: --devbox-frontend-port DEVBOX_FRONTEND_PORT" >&2 + exit 1 + fi + ;; + --devbox-backend-port | -B) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-backend-port' "$2" + shift 2 + else + printf "%s\n" "--devbox-backend-port requires an argument: --devbox-backend-port DEVBOX_BACKEND_PORT" >&2 + exit 1 + fi + ;; + # :flag.case + --devbox-image-repo | -R) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-image-repo' "$2" + shift 2 + else + printf "%s\n" "--devbox-image-repo requires an argument: --devbox-image-repo DEVBOX_IMAGE_REPO" >&2 + exit 1 + fi + ;; + # :flag.case + --devbox-image-name | -I) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-image-name' "$2" + shift 2 + else + printf "%s\n" "--devbox-image-name requires an argument: --devbox-image-name DEVBOX_IMAGE_NAME" >&2 + exit 1 + fi + ;; + # :flag.case + --devbox-image-tag | -T) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devbox-image-tag' "$2" + shift 2 + else + printf "%s\n" "--devbox-image-tag requires an argument: --devbox-image-tag DEVBOX_IMAGE_TAG" >&2 + exit 1 + fi + ;; + # :flag.case + --working-home | -w) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--working-home' "$2" + shift 2 + else + printf "%s\n" "--working-home requires an argument: --working-home WORKING_HOME" >&2 + exit 1 + fi + ;; + # :flag.case + --freeleaps-username | -U) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--freeleaps-username' "$2" + shift 2 + else + printf "%s\n" "--freeleaps-username requires an argument: --freeleaps-username FREELEAPS_USERNAME" >&2 + exit 1 + fi + ;; + # :flag.case + --freeleaps-password | -X) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--freeleaps-password' "$2" + shift 2 + else + printf "%s\n" "--freeleaps-password requires an argument: --freeleaps-password FREELEAPS_PASSWORD" >&2 + exit 1 + fi + ;; + # :flag.case + --use-local-component | -u) + if [[ -n ${2+x} ]]; then + add_arg '--use-local-component' "$2" + shift 2 + else + printf "%s\n" "--use-local-component requires an argument: --use-local-component USING_LOCAL_COMPONENT" >&2 + exit 1 + fi + ;; + # :flag.case + --devsvc-image-repo | -D) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devsvc-image-repo' "$2" + shift 2 + else + printf "%s\n" "--devsvc-image-repo requires an argument: --devsvc-image-repo DEVSVC_IMAGE_REPO" >&2 + exit 1 + fi + ;; + # :flag.case + --devsvc-image-name | -M) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devsvc-image-name' "$2" + shift 2 + else + printf "%s\n" "--devsvc-image-name requires an argument: --devsvc-image-name DEVSVC_IMAGE_NAME" >&2 + exit 1 + fi + ;; + # :flag.case + --devsvc-image-tag | -G) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--devsvc-image-tag' "$2" + shift 2 + else + printf "%s\n" "--devsvc-image-tag requires an argument: --devsvc-image-tag DEVSVC_IMAGE_TAG" >&2 + exit 1 + fi + ;; + # :flag.case + --notification-image-repo | -Y) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--notification-image-repo' "$2" + shift 2 + else + printf "%s\n" "--notification-image-repo requires an argument: --notification-image-repo NOTIFICATION_IMAGE_REPO" >&2 + exit 1 + fi + ;; + --notification-image-name | -K) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--notification-image-name' "$2" + shift 2 + else + printf "%s\n" "--notification-image-name requires an argument: --notification-image-name NOTIFICATION_IMAGE_NAME" >&2 + exit 1 + fi + ;; + --notification-image-tag | -Z) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--notification-image-tag' "$2" + shift 2 + else + printf "%s\n" "--notification-image-tag requires an argument: --notification-image-tag NOTIFICATION_IMAGE_TAG" >&2 + exit 1 + fi + ;; + # :flag.case + --content-image-repo | -C) + if [[ -n ${2+x} ]]; then + add_arg '--content-image-repo' "$2" + shift 2 + else + printf "%s\n" "--content-image-repo requires an argument: --content-image-repo FREELEAPS_CONTENT_IMAGE_REPO" >&2 + exit 1 + fi + ;; + # :flag.case + --content-image-name | -E) + if [[ -n ${2+x} ]]; then + add_arg '--content-image-name' "$2" + shift 2 + else + printf "%s\n" "--content-image-name requires an argument: --content-image-name FREELEAPS_CONTENT_IMAGE_NAME" >&2 + exit 1 + fi + ;; + # :flag.case + --content-image-tag | -H) + if [[ -n ${2+x} ]]; then + add_arg '--content-image-tag' "$2" + shift 2 + else + printf "%s\n" "--content-image-tag requires an argument: --content-image-tag FREELEAPS_CONTENT_IMAGE_TAG" >&2 + exit 1 + fi + ;; + # :flag.case + --central_storage-image-repo | -S) + if [[ -n ${2+x} ]]; then + add_arg '--central_storage-image-repo' "$2" + shift 2 + else + printf "%s\n" "--central_storage-image-repo requires an argument: --central_storage-image-repo FREELEAPS_CENTRAL_STORAGE_IMAGE_REPO" >&2 + exit 1 + fi + ;; + # :flag.case + --central_storage-image-name | -J) + if [[ -n ${2+x} ]]; then + add_arg '--central_storage-image-name' "$2" + shift 2 + else + printf "%s\n" "--central_storage-image-name requires an argument: --central_storage-image-name FREELEAPS_CENTRAL_STORAGE_IMAGE_NAME" >&2 + exit 1 + fi + ;; + # :flag.case + --central_storage-image-tag | -Q) + if [[ -n ${2+x} ]]; then + add_arg '--central_storage-image-tag' "$2" + shift 2 + else + printf "%s\n" "--central_storage-image-tag requires an argument: --central_storage-image-tag FREELEAPS_CENTRAL_STORAGE_IMAGE_TAG" >&2 + exit 1 + fi + ;; + # :flag.case + --authentication-image-repo | -V) + if [[ -n ${2+x} ]]; then + add_arg '--authentication-image-repo' "$2" + shift 2 + else + printf "%s\n" "--authentication-image-repo requires an argument: --authentication-image-repo FREELEAPS_AUTHENTICATION_IMAGE_REPO" >&2 + exit 1 + fi + ;; + # :flag.case + --authentication-image-name | -L) + if [[ -n ${2+x} ]]; then + add_arg '--authentication-image-name' "$2" + shift 2 + else + printf "%s\n" "--authentication-image-name requires an argument: --authentication-image-name FREELEAPS_AUTHENTICATION_IMAGE_NAME" >&2 + exit 1 + fi + ;; + # :flag.case + --authentication-image-tag | -W) + if [[ -n ${2+x} ]]; then + add_arg '--authentication-image-tag' "$2" + shift 2 + else + printf "%s\n" "--authentication-image-tag requires an argument: --authentication-image-tag FREELEAPS_AUTHENTICATION_IMAGE_TAG" >&2 + exit 1 + fi + ;; + # :flag.case + --force | -f) + # :flag.case_no_arg + add_arg '--force' '1' + shift + ;; + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + ;; + esac + done + + # :command.default_assignments + if [ -z "$(get_arg '--os')" ]; then + add_arg '--os' "auto" + fi + + if [ -z "$(get_arg '--arch')" ]; then + add_arg '--arch' "auto" + fi + + if [ -z "$(get_arg '--devbox-container-name')" ]; then + add_arg '--devbox-container-name' "devbox" + fi + + if [ -z "$(get_arg '--devbox-container-port')" ]; then + add_arg '--devbox-container-port' "22222" + fi + + if [ -z "$(get_arg '--devbox-frontend-port')" ]; then + add_arg '--devbox-frontend-port' "5173" + fi + + if [ -z "$(get_arg '--devbox-backend-port')" ]; then + add_arg '--devbox-backend-port' "8002" + fi + + if [ -z "$(get_arg '--devbox-image-repo')" ]; then + add_arg '--devbox-image-repo' "docker.io/freeleaps" + fi + + if [ -z "$(get_arg '--devbox-image-name')" ]; then + add_arg '--devbox-image-name' "devbox_v1" + fi + + if [ -z "$(get_arg '--devbox-image-tag')" ]; then + add_arg '--devbox-image-tag' "devbox_local" + fi + + if [ -z "$(get_arg '--devsvc-image-tag')" ]; then + add_arg '--devsvc-image-tag' "latest-linux-arm64" + fi + + if [ -z "$(get_arg '--content-image-tag')" ]; then + add_arg '--content-image-tag' "latest-linux-arm64" + fi + + if [ -z "$(get_arg '--central_storage-image-tag')" ]; then + add_arg '--central_storage-image-tag' "latest-linux-arm64" + fi + + if [ -z "$(get_arg '--authentication-image-tag')" ]; then + add_arg '--authentication-image-tag' "latest-linux-arm64" + fi + + if [ -z "$(get_arg '--working-home')" ]; then + add_arg '--working-home' "${HOME}/devbox" + fi + + if [ -z "$(get_arg '--use-local-component')" ]; then + add_arg '--use-local-component' "false" + fi +} + + +# :command.parse_requirements +devbox_deinit_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --help | -h) + long_usage=yes + devbox_deinit_usage + exit + ;; + *) + break + ;; + + esac + done + + # :command.command_filter + action="deinit" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --working-home | -w) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--working-home' "$2" + shift + shift + else + printf "%s\n" "--working-home requires an argument: --working-home WORKING_HOME" >&2 + exit 1 + fi + ;; + + # :flag.case + --clear-logs | -l) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--clear-logs' "$2" + shift + shift + else + printf "%s\n" "--clear-logs requires an argument: --clear-logs CLEAR_LOGS" >&2 + exit 1 + fi + ;; + + # :flag.case + --clear-repo | -r) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--clear-repo' "$2" + shift + shift + else + printf "%s\n" "--clear-repo requires an argument: --clear-repo CLEAR_REPO" >&2 + exit 1 + fi + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + + # :command.default_assignments + if [ -z "$(get_arg '--working-home')" ]; then + add_arg '--working-home' "${HOME}/devbox" + fi + if [ -z "$(get_arg '--clear-logs')" ]; then + add_arg '--clear-logs' "false" + fi + if [ -z "$(get_arg '--clear-repo')" ]; then + add_arg '--clear-repo' "false" + fi + +} + +# :command.parse_requirements +devbox_start_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --help | -h) + long_usage=yes + devbox_start_usage + exit + ;; + + + *) + break + ;; + + esac + done + + # :command.command_filter + action="start" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --component | -c) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--component' "$2" + shift + shift + else + printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 + exit 1 + fi + ;; + + --freeleaps-endpoint | -e) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--freeleaps-endpoint' "$2" + shift + shift + else + printf "%s\n" "--freeleaps-endpoint requires an argument: --freeleaps-endpoint FREELEAPS_ENDPOINT" >&2 + exit 1 + fi + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + + # :command.default_assignments + if [ -z "$(get_arg '--freeleaps-endpoint')" ]; then + add_arg '--freeleaps-endpoint' "false" + fi + +} + +# :command.parse_requirements +devbox_stop_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --help | -h) + long_usage=yes + devbox_stop_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.command_filter + action="stop" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --component | -c) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--component' "$2" + shift + shift + else + printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 + exit 1 + fi + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + +} + +# :command.parse_requirements +devbox_status_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --help | -h) + long_usage=yes + devbox_status_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.command_filter + action="status" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --component | -c) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--component' "$2" + shift + shift + else + printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 + exit 1 + fi + ;; + + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + +} + +# :command.parse_requirements +devbox_restart_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + --help | -h) + long_usage=yes + devbox_restart_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.command_filter + action="restart" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --component | -c) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--component' "$2" + shift + shift + else + printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 + exit 1 + fi + ;; + --freeleaps-endpoint | -e) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--freeleaps-endpoint' "$2" + shift + shift + else + printf "%s\n" "--freeleaps-endpoint requires an argument: --freeleaps-endpoint FREELEAPS_ENDPOINT" >&2 + exit 1 + fi + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + + # :command.default_assignments + if [ -z "$(get_arg '--freeleaps-endpoint')" ]; then + add_arg '--freeleaps-endpoint' "false" + fi + +} + + + +initialize() { + version="1.0.0" + long_usage="" + set -e + + # Use the following variables to define the environment variables and input parameters + args_keys=() + args_values=() + + deps_keys=() + deps_values=() + + # For each environment variable, add a line like the following: + env_var_names=() + input=() +} + +# :command.run +run() { + normalize_input "$@" + parse_requirements "${input[@]}" + + case "$action" in + "init") devbox_init_command ;; + "deinit") devbox_deinit_command ;; + "start") devbox_start_command ;; + "stop") devbox_stop_command ;; + "status") devbox_status_command ;; + "restart") devbox_restart_command ;; + esac +} +initialize +run "$@" diff --git a/devbox/devbox.local/cli/docker-compose.dev.arm64.new.yaml b/devbox/devbox.local/cli/docker-compose.dev.arm64.new.yaml new file mode 100644 index 0000000..7c2861e --- /dev/null +++ b/devbox/devbox.local/cli/docker-compose.dev.arm64.new.yaml @@ -0,0 +1,266 @@ +services: + gitea: + # For apple chip, add: platform: linux/amd64 + container_name: freeleaps2-gitea + platform: linux/${ARCH:-arm64} + image: gitea/gitea:latest + restart: always + ports: + - "3000:3000" + environment: + - DISABLE_REGISTRATION=true + - REQUIRE_SIGNIN_VIEW=true + volumes: + - ${WORKING_HOME}/freeleaps2-gitea:/data:Z + networks: + - devbox_freeleaps2-network + + chat: + container_name: freeleaps-chat + build: + context: ${WORKING_HOME}/freeleaps/apps + dockerfile: ${WORKING_HOME}/freeleaps/dockers/dev.chat.Dockerfile + args: + CONTAINER_APP_ROOT: app + restart: always + ports: + - 8012:8012 + environment: + - CERT_PATH=/app/certs + - EMAIL_FROM=freeleaps@freeleaps.com + - MONGODB_NAME=freeleaps2 + - MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ + - SITE_URL_ROOT=http://localhost + - JWT_SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b + - JWT_ALGORITHM=HS256 + - RABBITMQ_HOST=freeleaps2-rabbitmq + - RABBITMQ_PORT=5672 + - LOG_BASE_PATH=/app/log/freeleaps-chat + - BACKEND_LOG_FILE_NAME=freeleaps-chat.log + - APPLICATION_ACTIVITY_LOG=freeleaps-chat.application.log + - FREELEAPS_ENV=dev + - FREELEAPS_CHAT_ENDPOINT=http://freeleaps-alpha.com/api/chat/ + - FREELEAPS_DEVSVC_ENDPOINT=http://devsvc:8007/api/devsvc/ + - FREELEAPS_CONTENT_ENDPOINT=http://content:8013/api/content/ + - FREELEAPS_NOTIFICATION_ENDPOINT=http://notification:8003/api/notification/ + - FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://central_storage:8005/api/central_storage/ + - FREELEAPS_AUTHENTICATION_ENDPOINT=http://authentication:8004/api/auth/ + - CERT_PATH=/app/certs + - TZ=Asia/Shanghai + command: + # Use a conditional check for RabbitMQ in alpha profile + - /bin/sh + - -c + - | + uvicorn chat.main:app --reload --host=0.0.0.0 --port=8012 --workers 4 --timeout-keep-alive 120 --log-level info + volumes: + - type: bind + source: ${WORKING_HOME}/freeleaps/apps + target: /app/log/freeleaps-chat + networks: + - devbox_freeleaps2-network + + mongodb: + # For apple chip, add: platform: linux/amd64 + # For apple chip, you may want to downgrade to public mongo:4.4 for log support + container_name: freeleaps2-mongodb + platform: linux/${ARCH:-arm64} + image: mongo:latest + restart: always + ports: + - "27017:27017" + volumes: + - ${WORKING_HOME}/freeleaps2-mongodb-data:/data/db + networks: + - devbox_freeleaps2-network + + rabbitmq: + # For apple chip, add: platform: linux/amd64 + platform: linux/${ARCH:-arm64} + container_name: freeleaps2-rabbitmq + image: rabbitmq:latest + restart: always + ports: + - "5672:5672" + - "15672:15672" + volumes: + - ${WORKING_HOME}/freeleaps2-rabbitmq-data:/var/lib/rabbitmq + networks: + - devbox_freeleaps2-network + + devsvc: + container_name: devsvc + image: freeleaps/devsvc:${DEVSVC_IMAGE_TAG:-latest-linux-arm64} + restart: always + environment: + - APP_NAME=devsvc + - SERVICE_API_ACCESS_HOST=localhost + - SERVICE_API_ACCESS_PORT=8007 + - MONGODB_NAME=freeleaps2 + - MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ + - GITEA_TOKEN=6786dc398b77d2a9c454b1943019425049deb667 + - GITEA_URL=http://freeleaps2-gitea:3000 + - CODE_DEPOT_HTTP_PORT=3443 + - CODE_DEPOT_SSH_PORT=22 + - CODE_DEPOT_DOMAIN_NAME=localhost + - RABBITMQ_HOST=freeleaps2-rabbitmq + - RABBITMQ_PORT=5672 + - LOG_BASE_PATH=/app/log/devsvc + - BACKEND_LOG_FILE_NAME=devsvc.log + - APPLICATION_ACTIVITY_LOG=devsvc-application.log + ports: + - 8007:8007 + command: + - /bin/sh + - -c + - | + uvicorn webapi.main:app --reload --port=8007 --host=0.0.0.0 + volumes: + - type: bind + source: ${WORKING_HOME}/logs/devsvc + target: /app/log/devsvc + networks: + - devbox_freeleaps2-network + + central_storage: + container_name: central_storage + image: freeleaps/central_storage:${CENTRAL_STORAGE_IMAGE_TAG:-latest-linux-arm64} + # profiles: [ prod, alpha, dev ] + platform: linux/${ARCH:-arm64} + restart: always + environment: + - APP_NAME=central_storage + - MONGODB_NAME=freeleaps2 + - MONGODB_PORT=27017 + - MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ + - SERVICE_API_ACCESS_HOST=localhost + - SERVICE_API_ACCESS_PORT=8005 + - AZURE_STORAGE_DOCUMENT_API_KEY=Cg+wtKpHt6Bo6bTUtjic40cRNRZ8NCI3JYBY69BNPgFJARVx/c18iVC7cASbJfzukyu4pksyhUep+AStFdpH7Q== + - AZURE_STORAGE_DOCUMENT_API_ENDPOINT=https://freeleaps1document.blob.core.windows.net/ + - LOG_BASE_PATH=/app/log/central_storage + - BACKEND_LOG_FILE_NAME=central_storage.log + - APPLICATION_ACTIVITY_LOG=central_storage-application.log + ports: + - 8005:8005 + command: + - /bin/sh + - -c + - | + uvicorn webapi.main:app --reload --port=8005 --host=0.0.0.0 + networks: + - devbox_freeleaps2-network + volumes: + - type: bind + source: ${WORKING_HOME}/logs/central_storage + target: /app/log/central_storage + + authentication: + container_name: authentication + image: freeleaps/authentication:${AUTHENTICATION_IMAGE_TAG:-latest-linux-arm64} + # profiles: [ prod, alpha, dev ] + platform: linux/${ARCH:-arm64} + restart: always + environment: + - APP_NAME=authentication + - MONGODB_NAME=freeleaps2 + - MONGODB_PORT=27017 + - MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ + - SERVICE_API_ACCESS_HOST=localhost + - SERVICE_API_ACCESS_PORT=8004 + - LOG_BASE_PATH=/app/log/authentication + - BACKEND_LOG_FILE_NAME=authentication.log + - APPLICATION_ACTIVITY_LOG=authentication-application.log + - NOTIFICATION_WEBAPI_URL_BASE=http://notification:8003/api/notification/ + - DEVSVC_WEBAPI_URL_BASE=http://devsvc:8007/api/devsvc + - JWT_SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b + - JWT_ALGORITHM=HS256 + ports: + - 8004:8004 + command: + - /bin/sh + - -c + - | + uvicorn webapi.main:app --reload --port=8004 --host=0.0.0.0 + networks: + - devbox_freeleaps2-network + volumes: + - type: bind + source: ${WORKING_HOME}/logs/authentication + target: /app/log/authentication + + content: + container_name: content + image: freeleaps/content:${CONTENT_IMAGE_TAG:-latest-linux-arm64} + # profiles: [ prod, alpha, dev ] + platform: linux/${ARCH:-arm64} + restart: always + environment: + - APP_NAME=content + - SERVICE_API_ACCESS_HOST=localhost + - SERVICE_API_ACCESS_PORT=8013 + - MONGODB_NAME=freeleaps2 + - MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ + - FREELEAPS_WWW_AS_AZURE_CLIENT_SECRET=jTu8Q~WceiK-5dfZB44Ww-K4fVGi3_5tHNWYYbdX + - CENTRAL_STORAGE_WEBAPI_URL_BASE=http://central_storage:8005/api/central_storage/ + - LOG_BASE_PATH=/app/log/content + - BACKEND_LOG_FILE_NAME=content.log + - APPLICATION_ACTIVITY_LOG=content-application.log + ports: + - 8013:8013 + command: + - /bin/sh + - -c + - | + uvicorn webapi.main:app --reload --port=8013 --host=0.0.0.0 + networks: + - devbox_freeleaps2-network + volumes: + - type: bind + source: ${WORKING_HOME}/logs/content + target: /app/log/content + + notification: + container_name: notification + image: freeleaps/notification:${NOTIFICATION_IMAGE_TAG:-latest-linux-arm64} + # profiles: [ prod, alpha, dev ] + platform: linux/${ARCH:-arm64} + restart: always + environment: + - APP_NAME=notification + - SERVICE_API_ACCESS_HOST=localhost + - SERVICE_API_ACCESS_PORT=8003 + - RABBITMQ_HOST=freeleaps2-rabbitmq + - RABBITMQ_PORT=5672 + - SYSTEM_USER_ID=117f191e810c19729de860aa + - SMS_FROM=+16898887156 + - EMAIL_FROM=freeleaps@freeleaps.com + - SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b + - SENDGRID_API_KEY=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 + - TWILIO_ACCOUNT_SID=ACf8c9283a6acda060258eadb29be58bc8 + - TWILIO_AUTH_TOKEN=120165c0550111ddfd58efc97dafc2fe + - LOG_BASE_PATH=/app/log/notification + - BACKEND_LOG_FILE_NAME=notification.log + - APPLICATION_ACTIVITY_LOG=notification-application.log + ports: + - 8003:8003 + command: + - /bin/sh + - -c + - | + uvicorn webapi.main:app --reload --port=8003 --host=0.0.0.0 + networks: + - devbox_freeleaps2-network + volumes: + - type: bind + source: ${WORKING_HOME}/logs/notification + target: /app/log/notification + +volumes: + freeleaps2-mongodb-data: + freeleaps2-gitea-data: + freeleaps2-rabbitmq-data: + + +networks: + devbox_freeleaps2-network: + external: true diff --git a/devbox/devbox.local/cli/gitea_data_backup.tar.gz b/devbox/devbox.local/cli/gitea_data_backup.tar.gz new file mode 100644 index 0000000..550787f Binary files /dev/null and b/devbox/devbox.local/cli/gitea_data_backup.tar.gz differ diff --git a/devbox/devbox.local/docker-compose.dev.arm64.new.yaml b/devbox/devbox.local/docker-compose.dev.arm64.new.yaml old mode 100755 new mode 100644