Skip to content

Instantly share code, notes, and snippets.

@jumping
Last active September 12, 2025 08:48
Show Gist options
  • Save jumping/dc32de8909f1e71a926724d6ce548a15 to your computer and use it in GitHub Desktop.
Save jumping/dc32de8909f1e71a926724d6ce548a15 to your computer and use it in GitHub Desktop.
Configure the runtime environment for the setup_step.sh script
#!/usr/bin/env bash
set -Eeuo pipefail
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S%z')] $*"
}
usage() {
cat <<'EOF'
Usage: run-setup.sh --secret-id <secret_id> [--setup-script </path/to/setup_step.sh>]
[--region <aws_region>] [--poll-interval <seconds>]
[--s3-region <region>] [--eks-cluster-name <name>] [--efs-id <fs-xxxx>]
[--once]
Parts:
1) Install base tools (awscli, db clients, efs utils, kubectl, eksctl, jq)
2) Continuously poll Secrets Manager, printing mysql/postgresql/redis/s3/efs info
3) Ensure kubeconfig, then call setup_step.sh with (s3_region, eks_cluster_name, efs_id)
Examples:
run-setup.sh --secret-id my/workshop/secret --setup-script /opt/aws-workshop/setup_step.sh
EOF
}
SECRET_ID=""
SETUP_SCRIPT="/opt/aws-workshop/setup_step.sh"
AWS_REGION="${AWS_REGION:-}"
POLL_INTERVAL=15
ONCE=0
S3_REGION_OVERRIDE=""
EKS_CLUSTER_NAME_OVERRIDE=""
EFS_ID_OVERRIDE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--secret-id) SECRET_ID="$2"; shift 2;;
--setup-script) SETUP_SCRIPT="$2"; shift 2;;
--region) AWS_REGION="$2"; shift 2;;
--poll-interval) POLL_INTERVAL="$2"; shift 2;;
--s3-region) S3_REGION_OVERRIDE="$2"; shift 2;;
--eks-cluster-name) EKS_CLUSTER_NAME_OVERRIDE="$2"; shift 2;;
--efs-id) EFS_ID_OVERRIDE="$2"; shift 2;;
--once) ONCE=1; shift 1;;
-h|--help) usage; exit 0;;
*) log "Unknown argument: $1"; usage; exit 1;;
esac
done
if [[ -z "${SECRET_ID}" ]]; then
log "ERROR: --secret-id is required"
exit 1
fi
imds_region() {
set +e
TOKEN="$(curl -sS -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")"
REGION_DOC="$(curl -sS -H "X-aws-ec2-metadata-token: ${TOKEN}" http://169.254.169.254/latest/dynamic/instance-identity/document)"
echo "${REGION_DOC}" | jq -r .region 2>/dev/null
set -e
}
# -------------------------
# Part 1: base tools setup
# -------------------------
log "Installing base tools and CLIs..."
# Include your original commands
set -euxo pipefail
dnf -y update
dnf -y install awscli mariadb1011-client-utils postgresql15 amazon-efs-utils jq redis6
curl -sSL -o /usr/local/bin/kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.33.3/2025-08-03/bin/linux/amd64/kubectl
chmod +x /usr/local/bin/kubectl
curl -sLO https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_linux_amd64.tar.gz
tar -xzf eksctl_linux_amd64.tar.gz -C /usr/local/bin && chmod +x /usr/local/bin/eksctl && rm -f eksctl_linux_amd64.tar.gz
set +x
# Resolve region if not provided
if [[ -z "${AWS_REGION}" ]]; then
AWS_REGION="$(imds_region || true)"
fi
if [[ -z "${AWS_REGION}" ]]; then
AWS_REGION="$(aws configure get region || true)"
fi
if [[ -z "${AWS_REGION}" ]]; then
log "WARN: AWS region is not set and couldn't be auto-detected. Some AWS CLI calls may fail."
fi
log "Using AWS region: ${AWS_REGION:-<unset>}"
fetch_secret_json() {
set +e
local out
out="$(aws secretsmanager get-secret-value --secret-id "${SECRET_ID}" ${AWS_REGION:+--region "${AWS_REGION}"} --query SecretString --output text 2>/dev/null)"
local rc=$?
set -e
if [[ $rc -ne 0 || -z "${out}" || "${out}" == "None" ]]; then
echo ""
return 1
fi
echo "${out}"
}
print_service_info() {
local json="$1"
echo "---------------- Secrets Snapshot ----------------"
echo "Time: $(date '+%F %T%z') Secret: ${SECRET_ID} Region: ${AWS_REGION:-<unset>}"
if echo "${json}" | jq -e '.mysql? != null' >/dev/null 2>&1; then
echo "[MySQL]"
echo "${json}" | jq -r '.mysql | {host, port, username, dbname} | to_entries[] | "\(.key)=\(.value // "")"'
fi
if echo "${json}" | jq -e '.postgresql? != null' >/dev/null 2>&1; then
echo "[PostgreSQL]"
echo "${json}" | jq -r '.postgresql | {host, port, username, dbname} | to_entries[] | "\(.key)=\(.value // "")"'
fi
if echo "${json}" | jq -e '.redis? != null' >/dev/null 2>&1; then
echo "[Redis]"
echo "${json}" | jq -r '.redis | {endpoint, port} | to_entries[] | "\(.key)=\(.value // "")"'
fi
if echo "${json}" | jq -e '.s3? != null' >/dev/null 2>&1; then
echo "[S3]"
echo "${json}" | jq -r '.s3 | {bucket, region} | to_entries[] | "\(.key)=\(.value // "")"'
fi
if echo "${json}" | jq -e '.efs? != null' >/dev/null 2>&1; then
echo "[EFS]"
echo "${json}" | jq -r '.efs | {file_system_id, mount_target, dns} | to_entries[] | "\(.key)=\(.value // "")"'
fi
echo "--------------------------------------------------"
}
# 连接脚本生成:mysql.sh / psql.sh / redis.sh(运行时再取 Secret,不将密码落盘)
WORK_DIR="$(dirname "${SETUP_SCRIPT}" 2>/dev/null || echo /opt/aws-workshop)"
mkdir -p "${WORK_DIR}"
umask 077
generate_connection_scripts() {
local _json="$1"
# mysql.sh
cat > "${WORK_DIR}/mysql.sh" <<'EOS'
#!/usr/bin/env bash
set -euo pipefail
SECRET_ID="__SECRET_ID__"
AWS_REGION="__AWS_REGION__"
json="$(aws secretsmanager get-secret-value --secret-id "$SECRET_ID" ${AWS_REGION:+--region "$AWS_REGION"} --query SecretString --output text 2>/dev/null || true)"
if [[ -z "${json}" || "${json}" == "None" ]]; then
echo "[ERROR] Cannot fetch secret '${SECRET_ID}'."
exit 1
fi
host="$(echo "$json" | jq -r '.mysql.host // .mysql_host // empty')"
port="$(echo "$json" | jq -r '.mysql.port // .mysql_port // 3306')"
user="$(echo "$json" | jq -r '.mysql.username // .mysql_username // empty')"
pass="$(echo "$json" | jq -r '.mysql.password // .mysql_password // empty')"
db="$(echo "$json" | jq -r '.mysql.dbname // .mysql_database // empty')"
if ! command -v mysql >/dev/null 2>&1; then
echo "[ERROR] mysql client not found. Please install mariadb client."
exit 1
fi
if [[ -z "$host" || -z "$user" ]]; then
echo "[ERROR] host or username missing in secret."
exit 1
fi
if [[ -n "$pass" ]]; then
MYSQL_PWD="$pass" exec mysql -h "$host" -P "$port" -u "$user" ${db:+"$db"}
else
exec mysql -h "$host" -P "$port" -u "$user" ${db:+"$db"}
fi
EOS
# psql.sh
cat > "${WORK_DIR}/psql.sh" <<'EOS'
#!/usr/bin/env bash
set -euo pipefail
SECRET_ID="__SECRET_ID__"
AWS_REGION="__AWS_REGION__"
json="$(aws secretsmanager get-secret-value --secret-id "$SECRET_ID" ${AWS_REGION:+--region "$AWS_REGION"} --query SecretString --output text 2>/dev/null || true)"
if [[ -z "${json}" || "${json}" == "None" ]]; then
echo "[ERROR] Cannot fetch secret '${SECRET_ID}'."
exit 1
fi
host="$(echo "$json" | jq -r '.postgresql.host // .postgres_host // empty')"
port="$(echo "$json" | jq -r '.postgresql.port // .postgres_port // 5432')"
user="$(echo "$json" | jq -r '.postgresql.username // .postgres_username // empty')"
pass="$(echo "$json" | jq -r '.postgresql.password // .postgres_password // empty')"
db="$(echo "$json" | jq -r '.postgresql.dbname // .postgres_database // .postgres // .workshop')"
if ! command -v psql >/dev/null 2>&1; then
echo "[ERROR] psql client not found. Please install postgresql client."
exit 1
fi
if [[ -n "$pass" ]]; then
PGPASSWORD="$pass" exec psql "host=$host port=$port user=$user dbname=${db:-postgres} sslmode=prefer"
else
exec psql "host=$host port=$port user=$user dbname=${db:-postgres} sslmode=prefer"
fi
EOS
# redis.sh
cat > "${WORK_DIR}/redis.sh" <<'EOS'
#!/usr/bin/env bash
set -euo pipefail
SECRET_ID="__SECRET_ID__"
AWS_REGION="__AWS_REGION__"
json="$(aws secretsmanager get-secret-value --secret-id "$SECRET_ID" ${AWS_REGION:+--region "$AWS_REGION"} --query SecretString --output text 2>/dev/null || true)"
if [[ -z "${json}" || "${json}" == "None" ]]; then
echo "[ERROR] Cannot fetch secret '${SECRET_ID}'."
exit 1
fi
host="$(echo "$json" | jq -r '.redis.endpoint // .redis_primary_endpoint // empty')"
port="$(echo "$json" | jq -r '.redis.port // .redis_primary_port // 6379')"
pass="$(echo "$json" | jq -r '.redis.password // empty')"
if ! command -v redis6-cli >/dev/null 2>&1; then
echo "[ERROR] redis6-cli not found. Install Redis CLI or connect from another host."
exit 1
fi
if [[ -n "$pass" ]]; then
REDISCLI_AUTH="$pass" exec redis-cli -h "$host" -p "$port"
else
exec redis6-cli -h "$host" -p "$port"
fi
EOS
# 将 SECRET_ID 和 AWS_REGION 写入连接脚本(不落盘密码)
sed -i "s|__SECRET_ID__|${SECRET_ID}|g" "${WORK_DIR}/mysql.sh" "${WORK_DIR}/psql.sh" "${WORK_DIR}/redis.sh"
sed -i "s|__AWS_REGION__|${AWS_REGION:-}|g" "${WORK_DIR}/mysql.sh" "${WORK_DIR}/psql.sh" "${WORK_DIR}/redis.sh"
chmod +x "${WORK_DIR}/mysql.sh" "${WORK_DIR}/psql.sh" "${WORK_DIR}/redis.sh"
log "Connection scripts refreshed at ${WORK_DIR}: mysql.sh, psql.sh, redis.sh"
}
# -------------------------
# Part 2: secrets polling
# -------------------------
log "Starting secrets polling for '${SECRET_ID}' every ${POLL_INTERVAL}s..."
SECRETS_JSON_ONCE="$(fetch_secret_json || true)"
if [[ -n "${SECRETS_JSON_ONCE}" ]]; then
print_service_info "${SECRETS_JSON_ONCE}"
generate_connection_scripts "${SECRETS_JSON_ONCE}"
else
log "Secret '${SECRET_ID}' not available yet."
fi
if [[ "${ONCE}" -eq 0 ]]; then
(
while true; do
json="$(fetch_secret_json || true)"
if [[ -n "${json}" ]]; then
print_service_info "${json}"
generate_connection_scripts "${json}"
else
log "Secret '${SECRET_ID}' not ready or cannot be fetched."
fi
sleep "${POLL_INTERVAL}"
done
) &
SECRETS_WATCH_PID=$!
fi
# -------------------------
# Part 3: ensure kubeconfig then call setup_step.sh
# -------------------------
ensure_kubeconfig() {
local eks_cluster_name="$1"
local region_for_eks="$2"
if [[ -z "${eks_cluster_name}" ]]; then
log "ERROR: EKS cluster name is empty; cannot configure kubeconfig."
return 1
fi
if [[ -z "${region_for_eks}" ]]; then
region_for_eks="${AWS_REGION:-}"
fi
if [[ -z "${region_for_eks}" ]]; then
log "WARN: Region for EKS not found; kubeconfig update may fail."
fi
mkdir -p /root/.kube
local max_attempts=10
local attempt=1
local sleep_seconds=6
while (( attempt <= max_attempts )); do
log "Updating kubeconfig (attempt ${attempt}/${max_attempts}) for cluster '${eks_cluster_name}' in region '${region_for_eks:-<unset>}''..."
set +e
aws eks update-kubeconfig --name "${eks_cluster_name}" ${region_for_eks:+--region "${region_for_eks}"} >/tmp/update-kubeconfig.log 2>&1
local rc=$?
set -e
if [[ $rc -eq 0 ]]; then
# Verify cluster connectivity
set +e
kubectl get nodes >/tmp/kubectl-nodes.log 2>&1
local krc=$?
set -e
if [[ $krc -eq 0 ]]; then
log "Kubeconfig updated and kubectl is able to reach the cluster."
return 0
else
log "kubectl cannot reach the cluster yet. Log:"
sed 's/^/[kubectl] /' /tmp/kubectl-nodes.log || true
fi
else
log "update-kubeconfig failed. Log:"
sed 's/^/[update-kubeconfig] /' /tmp/update-kubeconfig.log || true
fi
attempt=$((attempt + 1))
log "Retrying in ${sleep_seconds}s..."
sleep "${sleep_seconds}"
done
log "ERROR: Failed to configure kubeconfig after ${max_attempts} attempts."
return 1
}
resolve_values_and_invoke() {
local json="$1"
local s3_region="" eks_cluster_name="" efs_id=""
if [[ -n "${json}" ]]; then
s3_region="$(echo "${json}" | jq -r '.s3.region // empty' 2>/dev/null || true)"
eks_cluster_name="$(echo "${json}" | jq -r '.eks.cluster_name // empty' 2>/dev/null || true)"
efs_id="$(echo "${json}" | jq -r '.efs.file_system_id // empty' 2>/dev/null || true)"
fi
s3_region="${S3_REGION_OVERRIDE:-${s3_region}}"
eks_cluster_name="${EKS_CLUSTER_NAME_OVERRIDE:-${eks_cluster_name}}"
efs_id="${EFS_ID_OVERRIDE:-${efs_id}}"
if [[ -z "${s3_region}" ]]; then
s3_region="${AWS_REGION:-}"
fi
if [[ -z "${eks_cluster_name}" ]]; then
set +e
eks_cluster_name="$(aws eks list-clusters ${AWS_REGION:+--region "${AWS_REGION}"} --query 'clusters[0]' --output text 2>/dev/null)"
[[ "${eks_cluster_name}" == "None" ]] && eks_cluster_name=""
set -e
fi
if [[ -z "${efs_id}" ]]; then
set +e
efs_id="$(aws efs describe-file-systems ${AWS_REGION:+--region "${AWS_REGION}"} --query 'FileSystems[0].FileSystemId' --output text 2>/dev/null)"
[[ "${efs_id}" == "None" ]] && efs_id=""
set -e
fi
log "Resolved values:"
log " s3_region=${s3_region:-<empty>}"
log " eks_cluster_name=${eks_cluster_name:-<empty>}"
log " efs_id=${efs_id:-<empty>}"
if [[ ! -x "${SETUP_SCRIPT}" ]]; then
log "ERROR: setup script not found or not executable: ${SETUP_SCRIPT}"
return 1
fi
# Ensure kubeconfig before invoking setup_step.sh
ensure_kubeconfig "${eks_cluster_name}" "${AWS_REGION:-${s3_region:-}}"
log "Invoking: ${SETUP_SCRIPT} '${s3_region}' '${eks_cluster_name}' '${efs_id}'"
"${SETUP_SCRIPT}" --region "${s3_region}" --cluster-name "${eks_cluster_name}" --efs-id "${efs_id}"
}
resolve_values_and_invoke "${SECRETS_JSON_ONCE}"
if [[ "${ONCE}" -eq 0 && -n "${SECRETS_WATCH_PID:-}" ]]; then
log "Secrets polling is running in background with PID ${SECRETS_WATCH_PID}."
fi
log "run-setup.sh completed initial execution."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment