From 53bd5cc62013048d584325359db04483ee913fef Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Wed, 11 Feb 2026 00:32:34 -0800 Subject: [PATCH] refactor: Extract sub-functions from oracle and ionos create_server() (#376) Oracle create_server (60 lines -> 32 lines): - _encode_userdata_b64: base64-encode cloud-init data - _launch_oci_instance: OCI CLI launch call + shape config + error handling IONOS create_server (53 lines -> 47 lines): - _ionos_build_server_body: build JSON request body for server creation - _ionos_launch_and_attach: API call + volume attachment logic Agent: complexity-hunter Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Haiku 4.5 --- ionos/lib/common.sh | 90 ++++++++++++++++++++++++++------------------ oracle/lib/common.sh | 53 ++++++++++++++++---------- 2 files changed, 87 insertions(+), 56 deletions(-) diff --git a/ionos/lib/common.sh b/ionos/lib/common.sh index a15eedb0..e92d1cb2 100644 --- a/ionos/lib/common.sh +++ b/ionos/lib/common.sh @@ -385,6 +385,57 @@ for nic in nics: return 1 } +# Build JSON request body for IONOS server creation +# Usage: _ionos_build_server_body NAME CORES RAM +_ionos_build_server_body() { + local name="$1" cores="$2" ram="$3" + python3 -c " +import json +body = { + 'properties': { + 'name': '$name', + 'cores': $cores, + 'ram': $ram, + 'availabilityZone': 'AUTO', + 'cpuFamily': 'AMD_OPTERON' + } +} +print(json.dumps(body)) +" +} + +# Create an IONOS server instance via API and attach a boot volume +# Sets IONOS_SERVER_ID on success +# Usage: _ionos_launch_and_attach VOLUME_ID NAME CORES RAM +_ionos_launch_and_attach() { + local volume_id="$1" name="$2" cores="$3" ram="$4" + + log_warn "Creating server instance..." + local server_body + server_body=$(_ionos_build_server_body "$name" "$cores" "$ram") + + local server_response + server_response=$(ionos_api POST "/datacenters/${IONOS_DATACENTER_ID}/servers" "$server_body") + + if ionos_check_api_error "$server_response" "Failed to create server"; then + return 1 + fi + + IONOS_SERVER_ID=$(echo "$server_response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['id'])") + log_info "Server created: $IONOS_SERVER_ID" + export IONOS_SERVER_ID + + # Attach volume to server + log_warn "Attaching volume to server..." + local attach_response + attach_response=$(ionos_api POST "/datacenters/${IONOS_DATACENTER_ID}/servers/${IONOS_SERVER_ID}/volumes" "{\"id\": \"${volume_id}\"}") + + if ionos_check_api_error "$attach_response" "Failed to attach volume"; then + return 1 + fi + log_info "Volume attached successfully" +} + # Create a IONOS server with cloud-init create_server() { local name="$1" @@ -425,43 +476,8 @@ create_server() { local pub_path="${key_path}.pub" ionos_register_ssh_key "spawn-key-$(date +%s)" "$pub_path" "${IONOS_DATACENTER_ID}" || log_warn "SSH key registration failed, continuing anyway..." - # Create server instance - log_warn "Creating server instance..." - local server_body - server_body=$(python3 -c " -import json -body = { - 'properties': { - 'name': '$name', - 'cores': $cores, - 'ram': $ram, - 'availabilityZone': 'AUTO', - 'cpuFamily': 'AMD_OPTERON' - } -} -print(json.dumps(body)) -") - - local server_response - server_response=$(ionos_api POST "/datacenters/${IONOS_DATACENTER_ID}/servers" "$server_body") - - if ionos_check_api_error "$server_response" "Failed to create server"; then - return 1 - fi - - IONOS_SERVER_ID=$(echo "$server_response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['id'])") - log_info "Server created: $IONOS_SERVER_ID" - export IONOS_SERVER_ID - - # Attach volume to server - log_warn "Attaching volume to server..." - local attach_response - attach_response=$(ionos_api POST "/datacenters/${IONOS_DATACENTER_ID}/servers/${IONOS_SERVER_ID}/volumes" "{\"id\": \"${volume_id}\"}") - - if ionos_check_api_error "$attach_response" "Failed to attach volume"; then - return 1 - fi - log_info "Volume attached successfully" + # Create server and attach volume + _ionos_launch_and_attach "$volume_id" "$name" "$cores" "$ram" || return 1 # Wait for server IP _ionos_wait_for_server_ip || return 1 diff --git a/oracle/lib/common.sh b/oracle/lib/common.sh index d3d5531d..dd19d875 100644 --- a/oracle/lib/common.sh +++ b/oracle/lib/common.sh @@ -308,26 +308,15 @@ _get_instance_public_ip() { echo "${ip}" } -create_server() { - local name="${1}" - local shape="${OCI_SHAPE:-VM.Standard.E2.1.Micro}" +# Encode cloud-init userdata as base64 (macOS and Linux compatible) +_encode_userdata_b64() { + get_cloud_init_userdata | base64 -w0 2>/dev/null || get_cloud_init_userdata | base64 +} - log_warn "Creating OCI instance '${name}' (shape: ${shape})..." - - local image_id - image_id=$(_get_ubuntu_image_id "${shape}") || return 1 - - local ad - ad=$(_get_availability_domain) || return 1 - - local subnet_id="${OCI_SUBNET_ID:-}" - if [[ -z "${subnet_id}" ]]; then - subnet_id=$(_get_subnet_id) || return 1 - fi - - # Encode cloud-init userdata (macOS and Linux compatible) - local userdata_b64 - userdata_b64=$(get_cloud_init_userdata | base64 -w0 2>/dev/null || get_cloud_init_userdata | base64) +# Launch an OCI compute instance and return its OCID on stdout +# Usage: instance_id=$(_launch_oci_instance NAME SHAPE IMAGE_ID AD SUBNET_ID USERDATA_B64) +_launch_oci_instance() { + local name="${1}" shape="${2}" image_id="${3}" ad="${4}" subnet_id="${5}" userdata_b64="${6}" # Build shape config for flex shapes local shape_config_args=() @@ -359,6 +348,32 @@ create_server() { return 1 fi + echo "${instance_id}" +} + +create_server() { + local name="${1}" + local shape="${OCI_SHAPE:-VM.Standard.E2.1.Micro}" + + log_warn "Creating OCI instance '${name}' (shape: ${shape})..." + + local image_id + image_id=$(_get_ubuntu_image_id "${shape}") || return 1 + + local ad + ad=$(_get_availability_domain) || return 1 + + local subnet_id="${OCI_SUBNET_ID:-}" + if [[ -z "${subnet_id}" ]]; then + subnet_id=$(_get_subnet_id) || return 1 + fi + + local userdata_b64 + userdata_b64=$(_encode_userdata_b64) + + local instance_id + instance_id=$(_launch_oci_instance "${name}" "${shape}" "${image_id}" "${ad}" "${subnet_id}" "${userdata_b64}") || return 1 + export OCI_INSTANCE_ID="${instance_id}" export OCI_INSTANCE_NAME_ACTUAL="${name}"