Skip to content

Commit

Permalink
refactor(scripts): enhance error handling and logging for robustness (#…
Browse files Browse the repository at this point in the history
…21)

Improve error handling by using 'set -e -o pipefail' to ensure
scripts exit on errors. Refactor error handling functions for
clarity and consistency. Enhance logging by redirecting error
messages to the appropriate log files. Simplify main function
execution and ensure only JSON output is sent to stdout. Remove
hardcoded environment name in Azure template for flexibility.
  • Loading branch information
sachincool authored Dec 26, 2024
1 parent 58cd52c commit c1ec897
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 58 deletions.
2 changes: 1 addition & 1 deletion scripts/get_environment.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash

set -e -o pipefail
# Read input from stdin (Terraform external data source)
eval "$(jq -r '@sh "
CONTROL_PLANE_URL=\(.control_plane_url)
Expand Down
108 changes: 52 additions & 56 deletions scripts/setup_truefoundry_cluster.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
set -e
set -e -o pipefail

# Read input from stdin (Terraform external data source)
eval "$(jq -r '@sh "
Expand All @@ -13,28 +13,27 @@ TRUEFOUNDRY_STDOUT_FILE=\(.stdout_log_file)
TRUEFOUNDRY_STDERR_FILE=\(.stderr_log_file)
"')"


# Validate required parameters
[ -z "${CONTROL_PLANE_URL}" ] && handle_error "CONTROL_PLANE_URL is required" && return 1
[ -z "${API_KEY}" ] && handle_error "API_KEY is required" && return 1
[ -z "${CLUSTER_NAME}" ] && handle_error "CLUSTER_NAME is required" && return 1
[ -z "${CLUSTER_TYPE}" ] && handle_error "CLUSTER_TYPE is required" && return 1
# Error handling
function handle_error() {
local error_message="$1"
echo "[ERROR] $error_message" >&2
exit 1
}

# Logging functions
function log_info() {
echo "[INFO] $1" >> $TRUEFOUNDRY_STDOUT_FILE
echo "[INFO] $1" >> "$TRUEFOUNDRY_STDOUT_FILE"
}

function log_error() {
echo "[ERROR] $1" >> $TRUEFOUNDRY_STDERR_FILE
echo "[ERROR] $1" >> "$TRUEFOUNDRY_STDERR_FILE"
}

# Error handling
function handle_error() {
log_error "$1"
jq -n --arg error "$1" '{"error": $error}'
exit 1
}
# Validate required parameters
[ -z "${CONTROL_PLANE_URL}" ] && handle_error "CONTROL_PLANE_URL is required"
[ -z "${API_KEY}" ] && handle_error "API_KEY is required"
[ -z "${CLUSTER_NAME}" ] && handle_error "CLUSTER_NAME is required"
[ -z "${CLUSTER_TYPE}" ] && handle_error "CLUSTER_TYPE is required"

# HTTP request handler
function make_request() {
Expand All @@ -44,7 +43,6 @@ function make_request() {
local expected_status_codes="$4"
local response_file=$(mktemp)
local http_code_file=$(mktemp)

log_info "make_request: Making ${method} request to ${url}"

local curl_cmd="curl -s -X ${method} \
Expand All @@ -54,129 +52,127 @@ function make_request() {

[ -n "$body" ] && curl_cmd="$curl_cmd -d '${body}'"

# Execute request and capture response, redirect all output to stderr
eval "${curl_cmd} '${url}'" > "${response_file}" 2>&2
# Execute request and capture response
eval "${curl_cmd} '${url}'" > "${response_file}" 2>>"$TRUEFOUNDRY_STDERR_FILE"
local curl_exit_code=$?

# Get HTTP status code, redirect all output to stderr
eval "${curl_cmd} -o /dev/null -w '%{http_code}' '${url}'" > "${http_code_file}" 2>&2
# Get HTTP status code
eval "${curl_cmd} -o /dev/null -w '%{http_code}' '${url}'" > "${http_code_file}" 2>>"$TRUEFOUNDRY_STDERR_FILE"
local http_code=$(<"${http_code_file}")

# Cleanup
rm -f "${http_code_file}"

# Validate response
if [ $curl_exit_code -ne 0 ]; then
local error_msg="Curl command failed with exit code: ${curl_exit_code}"
rm -f "${response_file}"
handle_error "$error_msg"
return 1
fi

if [[ ! ",$expected_status_codes," =~ ,"${http_code}", ]]; then
log_error "Request failed with status code: ${http_code}"
local error_msg="Request failed with status code: ${http_code}"
log_error "$error_msg"
log_error "Response body:"
cat "${response_file}" >&2
cat "${response_file}" >> "$TRUEFOUNDRY_STDERR_FILE"
rm -f "${response_file}"
handle_error "$error_msg"
return 1
fi

# Output response to stdout but only within a function call
# Output response
cat "${response_file}"
rm -f "${response_file}"
return 0
}


function create_cluster() {
log_info "create_cluster: Creating cluster..."

[-z "$CLUSTER_CONFIG_BASE64"] && handle_error "$CLUSTER_CONFIG_BASE64 is required" && return 1
[ -z "$CLUSTER_CONFIG_BASE64" ] && handle_error "CLUSTER_CONFIG_BASE64 is required"

local manifest=$(echo "$CLUSTER_CONFIG_BASE64" | base64 -d)
[ $? -ne 0 ] && handle_error "Failed to decode CLUSTER_CONFIG_BASE64"

log_info "create_cluster: cluster manifest ${manifest}"
local response=$(make_request "PUT" "${CONTROL_PLANE_URL}/api/svc/v1/cluster/" "${manifest}" "200,201") || \
handle_error "create_cluster: Failed to create cluster"
local response=$(make_request "PUT" "${CONTROL_PLANE_URL}/api/svc/v1/cluster/" "${manifest}" "200,201")
[ $? -ne 0 ] && handle_error "Failed to create cluster"

log_info "create_cluster: Response $response"

local cluster_id=$(echo "${response}" | jq -r '.id') || \
handle_error "create_cluster: Failed to parse cluster response"
local cluster_id=$(echo "${response}" | jq -r '.id')
[ $? -ne 0 ] && handle_error "Failed to parse cluster response"

log_info "create_cluster: Cluster ID $cluster_id"

[ -z "${cluster_id}" ] && handle_error "create_cluster: No cluster ID found in response" && return 1
[ -z "${cluster_id}" ] && handle_error "No cluster ID found in response"

echo "${cluster_id}"
}

function get_cluster_token() {
local cluster_id="$1"
[ -z "$cluster_id" ] && handle_error "Cluster ID is required for token generation"
log_info "get_cluster_token: Getting cluster token..."

local response=$(make_request "GET" \
"${CONTROL_PLANE_URL}/api/svc/v1/cluster/${cluster_id}/token" \
"" "200") || handle_error "Failed to get cluster token"
"" "200")
[ $? -ne 0 ] && handle_error "Failed to get cluster token"

local token=$(echo "${response}" | jq -r '.clusterToken') || \
handle_error "Failed to parse cluster token response"

[ -z "${token}" ] && handle_error "No cluster token found in response" && return 1
local token=$(echo "${response}" | jq -r '.clusterToken')
[ $? -ne 0 ] && handle_error "Failed to parse cluster token response"
[ -z "${token}" ] && handle_error "No cluster token found in response"

echo "${token}"
}

# Provider operations
function setup_provider_account() {
[ -z "$PROVIDER_CONFIG_BASE64" ] && handle_error "PROVIDER_CONFIG_BASE64 is required"

[ -z "$PROVIDER_CONFIG_BASE64" ] && handle_error "$CLUSTER_CONFIG_BASE64 is required" && return 1

log_info "setup_provider_account: Creating provider account..."
local provider_manifest=$(echo "$PROVIDER_CONFIG_BASE64" | base64 -d)
[ $? -ne 0 ] && handle_error "Failed to decode PROVIDER_CONFIG_BASE64"

log_info "setup_provider_account: provider account manifest ${provider_manifest}"
local response=$(make_request "PUT" \
"${CONTROL_PLANE_URL}/api/svc/v1/provider-accounts/" \
"${provider_manifest}" \
"200,201") || handle_error "setup_provider_account: Failed to create provider account"
"200,201")
[ $? -ne 0 ] && handle_error "Failed to create provider account"

log_info "setup_provider_account: Provider account created successfully"
}

# Main execution
function main() {
# Capture all output in variables to prevent unwanted stdout
local environment_name
local cluster_manifest
local cluster_id
local cluster_token
local tenant_name

# Verify platform health
log_info "main: Checking platform health..."
make_request "GET" "${CONTROL_PLANE_URL}/api/svc/" "" "200" >/dev/null || \
handle_error "Platform health check failed"
make_request "GET" "${CONTROL_PLANE_URL}/api/svc/" "" "200" >/dev/null || handle_error "Platform health check failed"

# Setup provider account if configured and cluster type is not generic
if [ "${CLUSTER_TYPE}" != "generic" ]; then
setup_provider_account
fi

cluster_id=$(create_cluster)
cluster_token=$(get_cluster_token "${cluster_id}")
local cluster_id
cluster_id=$(create_cluster) || handle_error "Failed to create cluster"

local cluster_token
cluster_token=$(get_cluster_token "${cluster_id}") || handle_error "Failed to get cluster token"

log_info "main: cluster_id=$cluster_id"
log_info "main: cluster_token=$cluster_token"

# Output only the final JSON result to stdout
# Output the final JSON result to stdout
jq -n \
--arg cluster_id "$cluster_id" \
--arg cluster_token "$cluster_token" \
'{
cluster_id: $cluster_id,
cluster_token: $cluster_token,
cluster_token: $cluster_token
}'
}

# Execute main function and ensure only JSON output goes to stdout
output=$(main)
echo "$output"
# Execute main function directly
main
2 changes: 1 addition & 1 deletion templates/cluster/azure.json.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
}
],
"cluster_type": "${cluster_type}",
"environment_names": ["${env_name}", "prod"]
"environment_names": ["${env_name}"]
%{ if container_registry_enabled },
"default_registry_fqn": "${tenant_name}:${account_type}:${cluster_name}:docker-registry:registry"
%{ endif }
Expand Down

0 comments on commit c1ec897

Please sign in to comment.