231 lines
7.5 KiB
Bash
Executable File
231 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# -------------------------------
|
||
# Detect Terraform binary: tofu vs terraform
|
||
# -------------------------------
|
||
if command -v tofu &>/dev/null; then
|
||
TF_BIN="tofu"
|
||
elif command -v terraform &>/dev/null; then
|
||
TF_BIN="terraform"
|
||
else
|
||
echo "❌ Neither 'terraform' nor 'tofu' found in PATH"
|
||
exit 1
|
||
fi
|
||
|
||
echo "ℹ️ Using $TF_BIN for Terraform operations"
|
||
|
||
# -------------------------------
|
||
# Ensure CF API token
|
||
# -------------------------------
|
||
CF_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}"
|
||
if [[ -z "${CF_API_TOKEN}" ]]; then
|
||
echo "Please set CF_API_TOKEN before running this script."
|
||
exit 1
|
||
fi
|
||
|
||
# -------------------------------
|
||
# Helper: fetch paginated results from Cloudflare API
|
||
# -------------------------------
|
||
cf_paginate() {
|
||
local endpoint="$1"
|
||
local page=1
|
||
local per_page=100
|
||
while :; do
|
||
local result
|
||
result=$(curl -s -X GET "${endpoint}?page=${page}&per_page=${per_page}" \
|
||
-H "Authorization: Bearer ${CF_API_TOKEN}" \
|
||
-H "Content-Type: application/json")
|
||
local items
|
||
items=$(echo "${result}" | jq -r '.result[]? | @base64')
|
||
[[ -z "$items" ]] && break
|
||
echo "$items"
|
||
local total_pages
|
||
total_pages=$(echo "$result" | jq -r '.result_info.total_pages')
|
||
((page++))
|
||
[[ $page -gt $total_pages ]] && break
|
||
done
|
||
}
|
||
|
||
# -------------------------------
|
||
# Generate Cloudflare resources using cf-terraforming
|
||
# -------------------------------
|
||
generate_resources() {
|
||
echo "🔧 Generating Cloudflare resources via cf-terraforming..."
|
||
local output_file="cloudflare_resource_gen.tf"
|
||
> "${output_file}"
|
||
|
||
resources=(
|
||
cloudflare_account
|
||
cloudflare_account_member
|
||
cloudflare_account_subscription
|
||
cloudflare_address_map
|
||
cloudflare_argo_tiered_caching
|
||
cloudflare_authenticated_origin_pulls
|
||
cloudflare_authenticated_origin_pulls_certificate
|
||
cloudflare_bot_management
|
||
cloudflare_certificate_pack
|
||
cloudflare_content_scanning_expression
|
||
cloudflare_custom_hostname
|
||
cloudflare_custom_hostname_fallback_origin
|
||
cloudflare_d1_database
|
||
cloudflare_dns_firewall
|
||
cloudflare_dns_record
|
||
cloudflare_dns_zone_transfers_acl
|
||
cloudflare_dns_zone_transfers_incoming
|
||
cloudflare_dns_zone_transfers_outgoing
|
||
cloudflare_dns_zone_transfers_peer
|
||
cloudflare_dns_zone_transfers_tsig
|
||
cloudflare_email_routing_address
|
||
cloudflare_email_routing_catch_all
|
||
cloudflare_email_routing_dns
|
||
cloudflare_email_routing_rule
|
||
cloudflare_email_routing_settings
|
||
cloudflare_filter
|
||
cloudflare_healthcheck
|
||
cloudflare_hostname_tls_setting
|
||
cloudflare_keyless_certificate
|
||
cloudflare_leaked_credential_check
|
||
cloudflare_leaked_credential_check_rule
|
||
cloudflare_list_item
|
||
cloudflare_load_balancer
|
||
cloudflare_load_balancer_monitor
|
||
cloudflare_load_balancer_pool
|
||
cloudflare_logpull_retention
|
||
cloudflare_logpush_job
|
||
cloudflare_magic_wan_static_route
|
||
cloudflare_managed_transforms
|
||
cloudflare_mtls_certificate
|
||
cloudflare_notification_policy
|
||
cloudflare_notification_policy_webhooks
|
||
cloudflare_observatory_scheduled_test
|
||
cloudflare_origin_ca_certificate
|
||
cloudflare_page_rule
|
||
cloudflare_page_shield_policy
|
||
cloudflare_pages_domain
|
||
cloudflare_pages_project
|
||
cloudflare_queue
|
||
cloudflare_queue_consumer
|
||
cloudflare_r2_bucket
|
||
cloudflare_r2_custom_domain
|
||
cloudflare_r2_managed_domain
|
||
cloudflare_rate_limit
|
||
cloudflare_regional_hostname
|
||
cloudflare_regional_tiered_cache
|
||
cloudflare_registrar_domain
|
||
cloudflare_ruleset
|
||
cloudflare_snippet_rules
|
||
cloudflare_snippets
|
||
cloudflare_spectrum_application
|
||
cloudflare_stream
|
||
cloudflare_stream_key
|
||
cloudflare_stream_live_input
|
||
cloudflare_stream_watermark
|
||
cloudflare_stream_webhook
|
||
cloudflare_tiered_cache
|
||
cloudflare_total_tls
|
||
cloudflare_turnstile_widget
|
||
cloudflare_url_normalization_settings
|
||
cloudflare_user
|
||
cloudflare_waiting_room
|
||
cloudflare_waiting_room_event
|
||
cloudflare_waiting_room_rules
|
||
cloudflare_waiting_room_settings
|
||
cloudflare_web3_hostname
|
||
cloudflare_web_analytics_rule
|
||
cloudflare_web_analytics_site
|
||
cloudflare_workers_cron_trigger
|
||
cloudflare_workers_custom_domain
|
||
cloudflare_workers_deployment
|
||
cloudflare_workers_for_platforms_dispatch_namespace
|
||
cloudflare_workers_kv_namespace
|
||
cloudflare_workers_script_subdomain
|
||
cloudflare_zone
|
||
cloudflare_zone_cache_reserve
|
||
cloudflare_zone_cache_variants
|
||
cloudflare_zone_dnssec
|
||
cloudflare_zone_lockdown
|
||
cloudflare_zone_setting
|
||
)
|
||
|
||
for r in "${resources[@]}"; do
|
||
echo "Generating $r ..."
|
||
cf-terraforming generate \
|
||
--token "${CF_API_TOKEN}" \
|
||
--resource-type "${r}" >> "${output_file}" || true
|
||
done
|
||
|
||
echo "✅ Terraform resources generated in ${output_file}"
|
||
}
|
||
|
||
# -------------------------------
|
||
# Import Cloudflare resources into state using cf-terraforming
|
||
# -------------------------------
|
||
import_zone_resources() {
|
||
local zone_id="$1"
|
||
local zone_name="$2"
|
||
|
||
echo "⏳ Importing zone $zone_name ..."
|
||
cf-terraforming import \
|
||
--token "${CF_API_TOKEN}" \
|
||
--modern-import-block \
|
||
--resource-type cloudflare_zone \
|
||
--resource-id "$zone_id" >> cloudflare_resource_imp.tf || true
|
||
echo "✅ Imported cloudflare_zone for $zone_name"
|
||
|
||
echo "🔄 Importing DNS records for $zone_name ..."
|
||
cf-terraforming import \
|
||
--token "${CF_API_TOKEN}" \
|
||
--zone "$zone_id" \
|
||
--modern-import-block \
|
||
--resource-type cloudflare_dns_record >> cloudflare_resource_imp.tf || true
|
||
echo "✅ Imported DNS records for $zone_name"
|
||
|
||
# Optional: import other zone-level resources
|
||
for res in cloudflare_argo_tiered_caching cloudflare_email_routing_settings cloudflare_tiered_cache cloudflare_zone_dnssec; do
|
||
cf-terraforming import \
|
||
--token "${CF_API_TOKEN}" \
|
||
--resource-type "$res" \
|
||
--modern-import-block \
|
||
--resource-id "$zone_id" >> cloudflare_resource_imp.tf || true
|
||
echo "✅ Imported $res for $zone_name"
|
||
done
|
||
}
|
||
|
||
# -------------------------------
|
||
# Main
|
||
# -------------------------------
|
||
echo "Choose an option:"
|
||
echo "1) Generate Cloudflare Terraform resources"
|
||
echo "2) Import Cloudflare Terraform resources into state"
|
||
read -rp "Enter 1 or 2: " choice
|
||
|
||
case "$choice" in
|
||
1)
|
||
generate_resources
|
||
;;
|
||
2)
|
||
echo "🔄 Fetching zones..."
|
||
zones=$(cf_paginate "https://api.cloudflare.com/client/v4/zones")
|
||
declare -A zone_map
|
||
while read -r z; do
|
||
zname=$(echo "$z" | base64 --decode | jq -r '.name')
|
||
zid=$(echo "$z" | base64 --decode | jq -r '.id')
|
||
zone_map["$zname"]="$zid"
|
||
done <<< "$zones"
|
||
|
||
echo "⚡ Found ${#zone_map[@]} zones."
|
||
|
||
for zone_name in "${!zone_map[@]}"; do
|
||
zid="${zone_map[$zone_name]}"
|
||
import_zone_resources "$zid" "$zone_name"
|
||
done
|
||
;;
|
||
*)
|
||
echo "Invalid option. Enter 1 or 2."
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
echo "🎉 All operations completed!"
|