From fe7b8cb3f8609fe2cfadc161c0b125124ebd7910 Mon Sep 17 00:00:00 2001 From: A <6723574+louisgv@users.noreply.github.com> Date: Fri, 13 Feb 2026 22:15:06 +0000 Subject: [PATCH] refactor: decompose webdock create_server and koyeb ensure_koyeb_cli into focused helpers 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: Claude Opus 4.6 (1M context) --- koyeb/lib/common.sh | 49 +++++++++++++++++--------- webdock/lib/common.sh | 82 ++++++++++++++++++++++++++----------------- 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/koyeb/lib/common.sh b/koyeb/lib/common.sh index 9089eb1af..cc4838b39 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 26a26376e..fd3f89fe9 100644 --- a/webdock/lib/common.sh +++ b/webdock/lib/common.sh @@ -134,6 +134,53 @@ _wait_for_webdock_server() { WEBDOCK_SERVER_IP "Server" "${max_attempts}" } +# 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): + ids = [k['id'] for k in data if 'id' in k] +else: + ids = [] +print(json.dumps(ids)) +" 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}" @@ -141,27 +188,12 @@ create_server() { 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; } + _webdock_validate_inputs "$location_id" "$profile_slug" "$image_slug" "$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 " -import json, sys -data = json.loads(sys.stdin.read()) -if isinstance(data, list): - ids = [k['id'] for k in data if 'id' in k] -else: - ids = [] -print(json.dumps(ids)) -" 2>/dev/null || echo "[]") + 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" }