refactor: replace hand-rolled API wrapper and polling loop with shared helpers (#927)

- hostkey: replace 22-line raw curl wrapper with generic_cloud_api
  delegation (adds retry logic, standardizes METHOD ENDPOINT [BODY] signature)
- exoscale: replace 30-line hand-rolled polling loop with
  generic_wait_for_instance via thin CLI wrapper

Agent: complexity-hunter

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
A 2026-02-13 05:48:07 -08:00 committed by GitHub
parent ebc5a6cc2f
commit 84681fe092
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 54 deletions

View file

@ -165,38 +165,25 @@ get_server_name() {
get_validated_server_name "EXOSCALE_SERVER_NAME" "Enter server name: "
}
# Thin wrapper around exo CLI that matches the generic_wait_for_instance API
# signature (func METHOD ENDPOINT) so the shared polling loop can be reused.
# The endpoint is the instance ID.
_exoscale_instance_api() {
local _method="$1" # unused; exo CLI doesn't distinguish methods
local instance_id="$2"
exo compute instance show "$instance_id" -O json 2>/dev/null || echo '{}'
}
# Wait for Exoscale instance to become running and get its IP
# Sets: EXOSCALE_SERVER_IP
# Usage: _wait_for_exoscale_instance INSTANCE_ID [MAX_ATTEMPTS]
_wait_for_exoscale_instance() {
local instance_id="$1"
local max_attempts=${2:-60}
local attempt=1
log_step "Waiting for instance to become running..."
while [[ "$attempt" -le "$max_attempts" ]]; do
local status_json
status_json=$(exo compute instance show "$instance_id" -O json 2>/dev/null || echo '{}')
local status
status=$(echo "$status_json" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('state','unknown'))" 2>/dev/null || echo "unknown")
if [[ "$status" == "running" ]]; then
EXOSCALE_SERVER_IP=$(echo "$status_json" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('public-ip',''))" 2>/dev/null)
export EXOSCALE_SERVER_IP
if [[ -n "$EXOSCALE_SERVER_IP" ]]; then
log_info "Instance running: IP=$EXOSCALE_SERVER_IP"
return 0
fi
fi
log_step "Instance status: $status ($attempt/$max_attempts)"
sleep "${INSTANCE_STATUS_POLL_DELAY}"
attempt=$((attempt + 1))
done
log_error "Instance did not become running in time"
return 1
local max_attempts="${2:-60}"
generic_wait_for_instance _exoscale_instance_api "$instance_id" \
"running" "d.get('state','unknown')" \
"d.get('public-ip','')" \
EXOSCALE_SERVER_IP "Instance" "$max_attempts"
}
# Write cloud-init userdata to a temporary file for exo CLI

View file

@ -23,35 +23,20 @@ fi
readonly HOSTKEY_API_BASE="https://invapi.hostkey.com"
# Centralized curl wrapper for HOSTKEY API
# Delegates to generic_cloud_api for retry logic and error handling
# Usage: hostkey_api METHOD ENDPOINT [BODY]
hostkey_api() {
local endpoint="$1"
local body="${2:-}"
local method="$1"
local endpoint="$2"
local body="${3:-}"
if [[ -z "${HOSTKEY_API_KEY:-}" ]]; then
log_error "HOSTKEY_API_KEY is not set"
return 1
fi
local response
if [[ -n "$body" ]]; then
response=$(curl -s "${HOSTKEY_API_BASE}${endpoint}" \
-H "Authorization: Bearer ${HOSTKEY_API_KEY}" \
-H "Content-Type: application/json" \
-d "$body")
else
response=$(curl -s "${HOSTKEY_API_BASE}${endpoint}" \
-H "Authorization: Bearer ${HOSTKEY_API_KEY}")
fi
printf '%s' "$response"
generic_cloud_api "$HOSTKEY_API_BASE" "$HOSTKEY_API_KEY" "$method" "$endpoint" "$body"
}
# Test HOSTKEY API key validity
test_hostkey_token() {
local response
# Try to get server list as a simple auth test
response=$(curl -s "${HOSTKEY_API_BASE}/v1/services" \
-H "Authorization: Bearer ${HOSTKEY_API_KEY:-}" 2>&1)
response=$(hostkey_api GET "/v1/services" 2>&1) || true
if echo "$response" | grep -qi "unauthorized\|invalid\|error"; then
log_error "API Error: Invalid or expired HOSTKEY API key"
@ -80,7 +65,7 @@ ensure_hostkey_token() {
hostkey_check_ssh_key() {
local fingerprint="$1"
local response
response=$(hostkey_api "/ssh_keys")
response=$(hostkey_api GET "/ssh_keys")
if echo "$response" | grep -q "$fingerprint"; then
return 0
@ -99,7 +84,7 @@ hostkey_register_ssh_key() {
local register_body="{\"name\":\"$key_name\",\"public_key\":$json_pub_key}"
local register_response
register_response=$(hostkey_api "/ssh_keys" "$register_body")
register_response=$(hostkey_api POST "/ssh_keys" "$register_body")
if echo "$register_response" | grep -qi "error"; then
log_error "API Error: $(echo "$register_response" | grep -o '"message":"[^"]*"' || echo "$register_response")"
@ -227,7 +212,7 @@ create_server() {
'{name: $name, location: $location, preset: $preset, os: "ubuntu-24.04"}')
local response
response=$(hostkey_api "/eq/order_instance" "$order_body")
response=$(hostkey_api POST "/eq/order_instance" "$order_body")
if echo "$response" | grep -qi "error"; then
log_error "Failed to create HOSTKEY instance"
@ -268,7 +253,7 @@ destroy_server() {
log_step "Destroying instance $instance_id..."
local response
response=$(hostkey_api "/eq/terminate" "{\"id\":\"$instance_id\"}")
response=$(hostkey_api POST "/eq/terminate" "{\"id\":\"$instance_id\"}")
if echo "$response" | grep -qi "error"; then
log_error "Failed to destroy instance: $response"
@ -281,7 +266,7 @@ destroy_server() {
# List all HOSTKEY instances
list_servers() {
local response
response=$(hostkey_api "/v1/services")
response=$(hostkey_api GET "/v1/services")
local count
count=$(printf '%s' "$response" | jq 'length' 2>/dev/null || echo "0")