From 388770126fa9ca04757f4df9f818054e689fba9d Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:22:24 -0800 Subject: [PATCH] refactor: decompose webdock create_server and koyeb ensure_koyeb_cli into focused helpers (#1016) webdock/lib/common.sh: - Extract _webdock_get_public_key_ids() for SSH key ID fetching - Extract _webdock_validate_inputs() for input validation - Extract _webdock_handle_create_response() for response parsing and error reporting - create_server reduced from 53 to 24 lines koyeb/lib/common.sh: - Extract _koyeb_detect_os() for OS detection - Extract _koyeb_detect_arch() for architecture detection - Extract _koyeb_install_cli() for download and PATH setup - ensure_koyeb_cli reduced from 51 to 13 lines Agent: complexity-hunter Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) --- koyeb/lib/common.sh | 49 +++++++++++++++-------- webdock/lib/common.sh | 90 ++++++++++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 53 deletions(-) diff --git a/koyeb/lib/common.sh b/koyeb/lib/common.sh index 9089eb1a..cc4838b3 100644 --- a/koyeb/lib/common.sh +++ b/koyeb/lib/common.sh @@ -23,37 +23,36 @@ fi # Koyeb specific functions # ============================================================ -# Ensure Koyeb CLI is installed -ensure_koyeb_cli() { - if command -v koyeb &>/dev/null; then - log_info "Koyeb CLI available" - return 0 - fi - - log_step "Installing Koyeb CLI..." - - # Detect OS and architecture - local os="" - local arch="" - +# Detect OS name for binary downloads (darwin or linux) +# Outputs the OS name to stdout; returns 1 on unsupported OS +_koyeb_detect_os() { case "$(uname -s)" in - Darwin) os="darwin" ;; - Linux) os="linux" ;; + Darwin) echo "darwin" ;; + Linux) echo "linux" ;; *) log_error "Unsupported operating system: $(uname -s)" return 1 ;; esac +} +# Detect CPU architecture for binary downloads (amd64 or arm64) +# Outputs the arch name to stdout; returns 1 on unsupported architecture +_koyeb_detect_arch() { case "$(uname -m)" in - x86_64|amd64) arch="amd64" ;; - arm64|aarch64) arch="arm64" ;; + x86_64|amd64) echo "amd64" ;; + arm64|aarch64) echo "arm64" ;; *) log_error "Unsupported architecture: $(uname -m)" return 1 ;; esac +} +# Download and install the Koyeb CLI binary +# Usage: _koyeb_install_cli OS ARCH +_koyeb_install_cli() { + local os="$1" arch="$2" local install_dir="$HOME/.koyeb/bin" mkdir -p "$install_dir" @@ -72,6 +71,22 @@ ensure_koyeb_cli() { log_error "Koyeb CLI not found in PATH after installation" return 1 fi +} + +# Ensure Koyeb CLI is installed +ensure_koyeb_cli() { + if command -v koyeb &>/dev/null; then + log_info "Koyeb CLI available" + return 0 + fi + + log_step "Installing Koyeb CLI..." + + local os arch + os=$(_koyeb_detect_os) || return 1 + arch=$(_koyeb_detect_arch) || return 1 + + _koyeb_install_cli "$os" "$arch" || return 1 log_info "Koyeb CLI installed" } diff --git a/webdock/lib/common.sh b/webdock/lib/common.sh index 26a26376..fd3f89fe 100644 --- a/webdock/lib/common.sh +++ b/webdock/lib/common.sh @@ -134,26 +134,12 @@ _wait_for_webdock_server() { WEBDOCK_SERVER_IP "Server" "${max_attempts}" } -create_server() { - local name="$1" - local slug="${name}" - local location_id="${WEBDOCK_LOCATION:-fi}" - local profile_slug="${WEBDOCK_PROFILE:-webdockmicro}" - local image_slug="${WEBDOCK_IMAGE:-ubuntu2404}" - - # Validate env var inputs to prevent injection into Python code - validate_resource_name "$location_id" || { log_error "Invalid WEBDOCK_LOCATION"; return 1; } - validate_resource_name "$profile_slug" || { log_error "Invalid WEBDOCK_PROFILE"; return 1; } - validate_resource_name "$image_slug" || { log_error "Invalid WEBDOCK_IMAGE"; return 1; } - validate_resource_name "$slug" || { log_error "Invalid server slug"; return 1; } - - log_step "Creating Webdock server '$name' (profile: $profile_slug, location: $location_id)..." - - # Get all SSH public key IDs - local public_keys_response - public_keys_response=$(webdock_api GET "/account/publicKeys") - local public_key_ids - public_key_ids=$(echo "$public_keys_response" | python3 -c " +# Fetch all SSH public key IDs from the Webdock account +# Returns: JSON array of key IDs (e.g., [1, 2, 3]) or "[]" if none +_webdock_get_public_key_ids() { + local response + response=$(webdock_api GET "/account/publicKeys") + echo "$response" | python3 -c " import json, sys data = json.loads(sys.stdin.read()) if isinstance(data, list): @@ -161,7 +147,53 @@ if isinstance(data, list): else: ids = [] print(json.dumps(ids)) -" 2>/dev/null || echo "[]") +" 2>/dev/null || echo "[]" +} + +# Validate Webdock server creation inputs +# Usage: _webdock_validate_inputs LOCATION PROFILE IMAGE SLUG +_webdock_validate_inputs() { + validate_resource_name "$1" || { log_error "Invalid WEBDOCK_LOCATION"; return 1; } + validate_resource_name "$2" || { log_error "Invalid WEBDOCK_PROFILE"; return 1; } + validate_resource_name "$3" || { log_error "Invalid WEBDOCK_IMAGE"; return 1; } + validate_resource_name "$4" || { log_error "Invalid server slug"; return 1; } +} + +# Extract server slug from creation response or report failure +# Sets: WEBDOCK_SERVER_SLUG on success +# Usage: _webdock_handle_create_response RESPONSE +_webdock_handle_create_response() { + local response="$1" + if echo "$response" | grep -q '"slug"'; then + WEBDOCK_SERVER_SLUG=$(_extract_json_field "$response" "d['slug']") + export WEBDOCK_SERVER_SLUG + log_info "Server created: slug=$WEBDOCK_SERVER_SLUG" + return 0 + fi + log_error "Failed to create Webdock server" + log_error "API Error: $(extract_api_error_message "$response" "$response")" + log_warn "Common issues:" + log_warn " - Insufficient account balance" + log_warn " - Profile/location unavailable (try different WEBDOCK_PROFILE or WEBDOCK_LOCATION)" + log_warn " - Server limit reached" + log_warn " - Slug already in use" + log_warn "Check your dashboard: https://my.webdock.io/" + return 1 +} + +create_server() { + local name="$1" + local slug="${name}" + local location_id="${WEBDOCK_LOCATION:-fi}" + local profile_slug="${WEBDOCK_PROFILE:-webdockmicro}" + local image_slug="${WEBDOCK_IMAGE:-ubuntu2404}" + + _webdock_validate_inputs "$location_id" "$profile_slug" "$image_slug" "$slug" || return 1 + + log_step "Creating Webdock server '$name' (profile: $profile_slug, location: $location_id)..." + + local public_key_ids + public_key_ids=$(_webdock_get_public_key_ids) local body body=$(_webdock_build_server_body "$name" "$slug" "$location_id" "$profile_slug" "$image_slug" "$public_key_ids") @@ -169,21 +201,7 @@ print(json.dumps(ids)) local response response=$(webdock_api POST "/servers" "$body") - if echo "$response" | grep -q '"slug"'; then - WEBDOCK_SERVER_SLUG=$(echo "$response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['slug'])") - export WEBDOCK_SERVER_SLUG - log_info "Server created: slug=$WEBDOCK_SERVER_SLUG" - else - log_error "Failed to create Webdock server" - log_error "API Error: $(extract_api_error_message "$response" "$response")" - log_warn "Common issues:" - log_warn " - Insufficient account balance" - log_warn " - Profile/location unavailable (try different WEBDOCK_PROFILE or WEBDOCK_LOCATION)" - log_warn " - Server limit reached" - log_warn " - Slug already in use" - log_warn "Check your dashboard: https://my.webdock.io/" - return 1 - fi + _webdock_handle_create_response "$response" || return 1 _wait_for_webdock_server "$WEBDOCK_SERVER_SLUG" }