BIG-IP Wide-IP to F5XC DNSLB converter
This is a conceptual sample script that converts BIG-IP Wide-IP records to F5XC DNSLB records. This bash script can be run using a cron job to check for configuration changes and synchronize them to F5XC. We used the F5XC API to post and update the configuration.
You need to get an APIToken from your F5XC tenant and change the value on the POST commands on the script below.
Note: Since this is not a full-blown converter script, it is limited to handling only a single Wide-IP pool member. You need to configure a GTM pool to include the IP addresses that need to be load balanced. Check the main article for more details.
#!/bin/bash
# Get list of wide IPs
wideip_output=$(tmsh list gtm wideip all-properties one-line)
# Get list of Pool
pool_output=$(tmsh list gtm pool a one-line all-properties)
# Declare associative arrays
declare -A wideip_list
declare -A current_wideip_info
declare -A zone_array
declare -A subdomain_info
declare -A a_record_per_zone
declare -A pool_list
declare -A membersip_array
# Unset variables
function unset_arrays {
unset current_wideip_info name subdomain domain type aliases description status failure_rcode last_resort_pool load_balancing_decision_log metadata minimal_response partition persist_cidr_ipv4 persist_cidr_ipv6 persistence pool_lb_mode pools pool_cname topology_edns0 ttl_persistence poolnames poolnames_array zone_array subdomain_info a_record_per_zone dnslb_name pool_list membersip_array
}
# Print wide IP details
function print_wideip {
for wideip in "${!wideip_list[@]}"; do
echo "Wide IP: $wideip, Details: ${wideip_list[$wideip]}"
done
}
# Create Zone
function create_zone {
curl -X POST -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$zone\",\"namespace\":\"system\"},\"spec\":{\"primary\":{\"allow_http_lb_managed_records\":true},\"default_soa_parameters\":{},\"dnssec_mode\":{},\"rr_set_group\":[],\"soa_parameters\":{\"refresh\":3600,\"expire\":0,\"retry\":60,\"negative_ttl\":0,\"ttl\":0}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_zones
}
# Create DNSLB
function create_dnslb {
curl -X POST -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$dnslbname\",\"namespace\":\"system\",\"labels\":{},\"annotations\":{},\"disable\":false},\"spec\":{\"record_type\":\"A\",\"rule_list\":{\"rules\":[{\"geo_location_set\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"geo-1\",\"kind\":\"geo_location_set\"},\"pool\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"$xcdnslbpoolname\",\"kind\":\"dns_lb_pool\"},\"score\":100}]},\"response_cache\":{\"disable\":{}}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_load_balancers
}
# Loop through each line of output
while IFS= read -r line; do
pool_name=$(awk '{print $4}' <<< "$line")
dnslbpool_name=$(echo "$pool_name" | sed 's/[^a-zA-Z0-9]/-/g; s/.*/\L&/')
pool_type=$(awk '{print $3}' <<< "$line")
lbmode=$(grep -o 'load-balancing-mode [^ ]*' <<< "$line" | awk '{print $2}')
# Convert load_balancing_mode to lowercase if it is "ROUND_ROBIN"
if [[ "$lbmode" == "round-robin" ]]; then
lbmode="ROUND_ROBIN"
elif [[ "$lbmode" == "static-persistence" ]]; then
lbmode="STATIC_PERSIST"
elif [[ "$lbmode" == "global-availability" ]]; then
lbmode="PRIORITY"
elif [[ "$lbmode" == "ratio" ]]; then
lbmode="RATIO_MEMBER"
fi
# Extract members block using awk
#members=$(awk -F 'members {| }' '{print $2}' <<< "$line")
members=$(echo "$line" | grep -o -P '(?<=members \{ ).*?(?=\} \})')
membernames=$(echo "$members" | grep -oP '\S+(?=\s*{)')
# Temporary array to hold member IP addresses
declare -a temp_members_array
temp_members_array=($(awk -F ':' '{print $2}' <<< "$membernames"))
monitor=$(awk -F 'monitor ' '{print $2}' <<< "$line" | awk '{print $1}')
ttl=$(awk '{print $2}' <<< "$(grep -o 'ttl [^ ]*' <<< "$line")")
# Assign values to the associative array
membersip_array["$dnslbpool_name"]="${temp_members_array[@]}"
# Store extracted values in the array
pool_list["$dnslbpool_name"]="pool_type: $pool_type, lbmode: $lbmode, monitor: $monitor, members: ${membersip_array["$dnslbpool_name"]}, ttl: $ttl"
done <<< "$pool_output"
# Loop through each pool in the pool_list
for dnslbpool_name in "${!pool_list[@]}"; do
# Extract only the TTL value from the string
ttl=$(awk -F 'ttl: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}")
lbmode=$(awk -F 'lbmode: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}" | awk -F ',' '{print $1}')
members=$(awk -F 'members: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}" | awk -F ',' '{print $1}')
pool_type=$(awk -F 'pool_type: ' '{print $2}' <<< "${pool_list[$dnslbpool_name]}" | awk -F ',' '{print $1}')
# Check if pool_type is "a"
if [[ "$pool_type" == "a" ]]; then
# Initialize an empty string to store the JSON strings
members_string=""
# Loop through each record in the current zone
for ip in ${membersip_array["$dnslbpool_name"]}; do
# Create JSON string for each member and append to the existing string
members_string+="{\"ip_endpoint\":\"$ip\",\"ratio\":10,\"priority\":1},"
done
# Remove the trailing comma from the JSON string
members_string="${members_string%,}"
# Create DNSLB Pools
curl -X POST \
-H "Authorization: APIToken Rs0aGJm/lda/JmbE00c9lFXWw4I=" \
-H "Accept: application/json" \
-H "Access-Control-Allow-Origin: *" \
-H "x-volterra-apigw-tenant: cag-waap2023" \
-H "Content-Type: application/json" \
-d "{\"metadata\":{\"name\":\"$dnslbpool_name\",\"namespace\":\"system\"},\"spec\":{\"a_pool\":{\"members\":[$members_string],\"disable_health_check\":null,\"max_answers\":1},\"ttl\":\"$ttl\",\"load_balancing_mode\":\"$lbmode\"}}" \
"https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_lb_pools"
fi
done
# Unset variables to free up memory
unset pool_list membersip_array
# Loop through each line of output
while IFS= read -r line; do
# Extracting specific details using awk and sed based on the current line
name=$(echo "$line" | awk '{print $4}')
dnslb_name=$(echo "$name" | sed 's/\./-/g')
subdomain=$(echo "$name" | cut -d'.' -f1)
domain=$(echo "$name" | sed 's/^[^.]*\.//')
type=$(echo "$line" | awk '{print $3}')
aliases=$(echo "$line" | grep -o 'aliases [^}]*' | awk '{print $2}')
description=$(echo "$line" | grep -o 'description [^ ]*' | sed 's/description //')
status=$(echo "$line" | awk '{print $12}')
failure_rcode=$(echo "$line" | grep -o 'failure-rcode [^ ]*' | sed 's/failure-rcode //')
last_resort_pool=$(echo "$line" | grep -o 'last-resort-pool [^ ]*' | sed 's/last-resort-pool //')
load_balancing_decision_log=$(echo "$line" | grep -o 'load-balancing-decision-log-verbosity [^ ]*' | sed 's/load-balancing-decision-log-verbosity //')
metadata=$(echo "$line" | grep -o 'metadata [^ ]*' | sed 's/metadata //')
minimal_response=$(echo "$line" | grep -o 'minimal-response [^ ]*' | sed 's/minimal-response //')
partition=$(echo "$line" | grep -o 'partition [^ ]*' | sed 's/partition //')
persist_cidr_ipv4=$(echo "$line" | grep -o 'persist-cidr-ipv4 [^ ]*' | sed 's/persist-cidr-ipv4 //')
persist_cidr_ipv6=$(echo "$line" | grep -o 'persist-cidr-ipv6 [^ ]*' | sed 's/persist-cidr-ipv6 //')
persistence=$(echo "$line" | grep -o ' persistence [^ ]*' | sed 's/persistence //')
pool_lb_mode=$(echo "$line" | grep -o 'pool-lb-mode [^ ]*' | sed 's/pool-lb-mode //')
pools=$(echo "$line" | grep -o -P '(?<=pools \{ ).*?(?=\} \})')
pool_cname=$(echo "$line" | grep -o 'pools-cname [^ ]*' | sed 's/pools-cname //')
topology_edns0=$(echo "$line" | grep -o 'topology-prefer-edns0-client-subnet [^ ]*' | sed 's/topology-prefer-edns0-client-subnet //')
ttl_persistence=$(echo "$line" | grep -o 'ttl-persistence [^ ]*' | sed 's/ttl-persistence //')
# Use grep to find strings before "{"
poolnames=$(echo "$pools" | grep -oP '\S+(?=\s*{)' | sed 's/[^a-zA-Z0-9]/-/g; s/.*/\L&/')
# Convert matches to an array
readarray -t poolnames_array <<< "$poolnames"
# Store extracted values in the associative array
current_wideip_info=([Type]="$type" [Subdomain]="$subdomain" [Domain]="$domain" [Status]="$status" [DNSLB]="$dnslb_name" [Pools]="${poolnames_array[@]}" [Pool_LB_Mode]="$pool_lb_mode")
# Assign wideip_info to wideip_list
wideip_list["$name"]="${current_wideip_info[@]}"
# Add subdomains to zone_array
if [ -n "${zone_array[$domain]}" ]; then
zone_array["$domain"]="${zone_array[$domain]},$subdomain"
else
zone_array["$domain"]=$subdomain
fi
# Store subdomain information in subdomain_info array
subdomain_info["$subdomain"]="${current_wideip_info[@]}"
# Store subdomain type "a" and add it to the array for that zone
if [ "$type" == "a" ]; then
a_record_per_zone[$domain]="${a_record_per_zone[$domain]}${a_record_per_zone[$domain]:+,}$subdomain"
fi
done <<< "$wideip_output"
for zone in "${!zone_array[@]}"; do
create_zone
done
# Loop through each domain in a_record_per_zone and echo its A record subdomains
for domain in "${!a_record_per_zone[@]}"; do
echo "Domain: $domain"
echo "A Record Subdomains: ${a_record_per_zone[$domain]}"
echo "--------------------------"
# Initialize an empty string to store the JSON strings
a_records_string=""
# Loop through each record in the current zone
for record in ${a_record_per_zone[$domain]//,/ }; do
# Create JSON string for each A record and append to the existing string
xcdnslbpoolname=$(echo ${wideip_list[$record.$domain]} | awk '{for (i=6; i<=(NF-1); i++) {printf "%s", $i; if (i < NF-1) printf " "}}')
#echo "${a_record_per_zone[$domain]}"
#echo "xcdnslbpoolname: $xcdnslbpoolname"
# Check if xcdnslbpoolname has multiple strings
if [[ $xcdnslbpoolname == *" "* ]]; then
echo "Multiple strings found in xcdnslbpoolname"
# Split xcdnslbpoolname into an array based on space
IFS=' ' read -ra pool_names <<< "$xcdnslbpoolname"
# Initialize an empty string to store the JSON strings
pools_string=""
# Loop through each pool name in the array
for pool_name in "${pool_names[@]}"; do
# Create JSON string for each member and append to the existing string
pools_string+="{\"geo_location_set\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"geo-1\",\"kind\":\"geo_location_set\"},\"pool\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"$pool_name\",\"kind\":\"dns_lb_pool\"},\"score\":100},"
done
# Remove the trailing comma from the JSON string
pools_string="${pools_string%,}"
else
pools_string="{\"geo_location_set\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"geo-1\",\"kind\":\"geo_location_set\"},\"pool\":{\"tenant\":\"cag-waap2023-gwjvytud\",\"namespace\":\"system\",\"name\":\"$xcdnslbpoolname\",\"kind\":\"dns_lb_pool\"},\"score\":100}"
fi
dnslbname=$(echo "dnslb-$record-$domain" | sed 's/\./-/g')
#create_dnslb
curl -X POST -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$dnslbname\",\"namespace\":\"system\",\"labels\":{},\"annotations\":{},\"disable\":false},\"spec\":{\"record_type\":\"A\",\"rule_list\":{\"rules\":[$pools_string]},\"response_cache\":{\"disable\":{}}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_load_balancers
a_records_string+="{\"ttl\":3600,\"lb_record\": {\"name\":\"$record\",\"value\":{\"namespace\": \"system\",\"name\":\"$dnslbname\"}}},"
done
# Remove the trailing comma from the JSON string
a_records_string="${a_records_string%,}"
# Print the final JSON string
echo "$a_records_string"
#update zone record
curl -X PUT -H "Authorization: APIToken XXXXX" -H "Accept: application/json" -H "Access-Control-Allow-Origin: *" -H "x-volterra-apigw-tenant: cag-waap2023" -H "Content-Type: application/json" -d "{\"metadata\":{\"name\":\"$domain\",\"namespace\":\"system\"},\"spec\":{\"primary\":{\"allow_http_lb_managed_records\":true,\"default_rr_set_group\":[$a_records_string],\"default_soa_parameters\":{},\"dnssec_mode\":{},\"rr_set_group\":[],\"soa_parameters\":{\"refresh\":3600,\"expire\":0,\"retry\":60,\"negative_ttl\":0,\"ttl\":0}}}}" https://cag-waap2023.console.ves.volterra.io/api/config/dns/namespaces/system/dns_zones/$domain
done
unset_arrays
Published May 30, 2024
Version 1.0michelangelodorado
Employee
Joined December 02, 2019
No CommentsBe the first to comment