Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 59 additions & 18 deletions k8s/deployment/tests/validate_alb_target_group_capacity.bats
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ setup() {
export ALB_NAME="k8s-nullplatform-internet-facing"
export REGION="us-east-1"
export ALB_MAX_TARGET_GROUPS="98"
export DNS_TYPE="route53"

# Base CONTEXT
export CONTEXT='{
Expand Down Expand Up @@ -45,7 +46,7 @@ teardown() {
# Success flow
# =============================================================================
@test "validate_alb_target_group_capacity: success when under capacity" {
run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "🔍 Validating ALB target group capacity for 'k8s-nullplatform-internet-facing'..."
Expand All @@ -56,7 +57,7 @@ teardown() {
@test "validate_alb_target_group_capacity: displays debug info" {
export LOG_LEVEL="debug"

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "📋 ALB: k8s-nullplatform-internet-facing | Region: us-east-1 | Max target groups: 98"
Expand All @@ -81,7 +82,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ ALB 'k8s-nullplatform-internet-facing' has reached target group capacity: 98/98"
Expand Down Expand Up @@ -109,7 +110,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ ALB 'k8s-nullplatform-internet-facing' has reached target group capacity: 100/98"
Expand All @@ -121,7 +122,7 @@ teardown() {
@test "validate_alb_target_group_capacity: uses default ALB_MAX_TARGET_GROUPS of 98" {
unset ALB_MAX_TARGET_GROUPS

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "📋 ALB 'k8s-nullplatform-internet-facing' has 40 target groups (max: 98)"
Expand All @@ -130,7 +131,7 @@ teardown() {
@test "validate_alb_target_group_capacity: ALB_MAX_TARGET_GROUPS from env var" {
export ALB_MAX_TARGET_GROUPS="30"

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ ALB 'k8s-nullplatform-internet-facing' has reached target group capacity: 40/30"
Expand All @@ -140,7 +141,7 @@ teardown() {
export CONTEXT='{"providers":{"scope-configurations":{"networking":{"alb_max_target_groups":"30"}}}}'
export ALB_MAX_TARGET_GROUPS="98"

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ ALB 'k8s-nullplatform-internet-facing' has reached target group capacity: 40/30"
Expand All @@ -150,7 +151,7 @@ teardown() {
export CONTEXT='{"providers":{"container-orchestration":{"balancer":{"alb_max_target_groups":"30"}}}}'
export ALB_MAX_TARGET_GROUPS="98"

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ ALB 'k8s-nullplatform-internet-facing' has reached target group capacity: 40/30"
Expand All @@ -159,7 +160,7 @@ teardown() {
@test "validate_alb_target_group_capacity: scope-configurations takes priority over container-orchestration" {
export CONTEXT='{"providers":{"scope-configurations":{"networking":{"alb_max_target_groups":"100"}},"container-orchestration":{"balancer":{"alb_max_target_groups":"30"}}}}'

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "📋 ALB 'k8s-nullplatform-internet-facing' has 40 target groups (max: 100)"
Expand All @@ -169,7 +170,7 @@ teardown() {
export CONTEXT='{"providers":{"scope-configurations":{"networking":{"alb_max_target_groups":"100"}}}}'
export ALB_MAX_TARGET_GROUPS="30"

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "📋 ALB 'k8s-nullplatform-internet-facing' has 40 target groups (max: 100)"
Expand All @@ -190,7 +191,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ Failed to find load balancer 'k8s-nullplatform-internet-facing' in region 'us-east-1'"
Expand All @@ -212,7 +213,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ Load balancer 'k8s-nullplatform-internet-facing' not found in region 'us-east-1'"
Expand All @@ -233,7 +234,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ Failed to describe target groups for ALB 'k8s-nullplatform-internet-facing'"
Expand Down Expand Up @@ -261,7 +262,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "📋 ALB 'k8s-nullplatform-internet-facing' has 0 target groups (max: 98)"
Expand All @@ -283,7 +284,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "✅ ALB target group capacity validated: 97/98"
Expand All @@ -304,7 +305,7 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ Unexpected non-numeric target group count from ALB"
Expand All @@ -317,7 +318,7 @@ teardown() {
@test "validate_alb_target_group_capacity: fails when ALB_MAX_TARGET_GROUPS is non-numeric" {
export ALB_MAX_TARGET_GROUPS="abc"

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ ALB_MAX_TARGET_GROUPS must be a numeric value, got: 'abc'"
Expand All @@ -336,8 +337,48 @@ teardown() {
}
export -f aws

run bash "$SCRIPT"
run bash -c 'source "$SCRIPT"'

assert_equal "$status" "1"
assert_contains "$output" "❌ Load balancer 'k8s-nullplatform-internet-facing' not found in region 'us-east-1'"
}

# =============================================================================
# DNS_TYPE guard
# =============================================================================
@test "validate_alb_target_group_capacity: skips when DNS_TYPE is external_dns" {
export DNS_TYPE="external_dns"

run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
[[ "$output" != *"🔍 Validating ALB target group capacity"* ]]
}

@test "validate_alb_target_group_capacity: skips when DNS_TYPE is azure" {
export DNS_TYPE="azure"

run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
[[ "$output" != *"🔍 Validating ALB target group capacity"* ]]
}

@test "validate_alb_target_group_capacity: skips with debug message for non-route53 DNS" {
export DNS_TYPE="external_dns"
export LOG_LEVEL="debug"

run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "DNS type is 'external_dns', ALB target group validation only applies to route53, skipping"
}

@test "validate_alb_target_group_capacity: runs when DNS_TYPE is route53" {
export DNS_TYPE="route53"

run bash -c 'source "$SCRIPT"'

assert_equal "$status" "0"
assert_contains "$output" "🔍 Validating ALB target group capacity for 'k8s-nullplatform-internet-facing'..."
}
5 changes: 5 additions & 0 deletions k8s/deployment/validate_alb_target_group_capacity
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../utils/get_config_value"

if [[ "$DNS_TYPE" != "route53" ]]; then
log debug "📋 DNS type is '$DNS_TYPE', ALB target group validation only applies to route53, skipping"
return 0
fi

ALB_MAX_TARGET_GROUPS=$(get_config_value \
--env ALB_MAX_TARGET_GROUPS \
--provider '.providers["scope-configurations"].networking.alb_max_target_groups' \
Expand Down
97 changes: 52 additions & 45 deletions k8s/scope/networking/resolve_balancer
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

# Resolves the ALB name to use for the scope's ingress.
#
# Resolution priority:
# Resolution priority (when DNS_TYPE is route53):
# 1. Route53 — if a DNS record already exists for the scope domain,
# use the ALB it points to (ensures DNS/ingress consistency)
# 2. Load balancing — when additional balancers are configured, pick
# the ALB with the fewest HTTPS listener rules
# 3. Provider config — base ALB from scope-configurations or
# container-orchestration provider
#
# For non-route53 DNS types, only priority 3 (provider config) is used.
#
# Inputs (env vars):
# DNS_TYPE - DNS provider type (route53, azure, external_dns)
# INGRESS_VISIBILITY - "internet-facing" or "internal"
# CONTEXT - JSON with provider configuration
# REGION - AWS region (for elbv2 API calls)
Expand Down Expand Up @@ -142,64 +145,68 @@ else
)
fi

# Priority 1: Check Route53 for an existing DNS record
SCOPE_DOMAIN_VAL=$(echo "$CONTEXT" | jq -r '.scope.domain // empty')
EXISTING_ALB=""
if [[ "$DNS_TYPE" == "route53" ]]; then
# Priority 1: Check Route53 for an existing DNS record
SCOPE_DOMAIN_VAL=$(echo "$CONTEXT" | jq -r '.scope.domain // empty')
EXISTING_ALB=""

if [ -n "$SCOPE_DOMAIN_VAL" ]; then
EXISTING_ALB=$(get_alb_from_route53 "$SCOPE_DOMAIN_VAL" "$REGION" 2>/dev/null) || true
fi
if [ -n "$SCOPE_DOMAIN_VAL" ]; then
EXISTING_ALB=$(get_alb_from_route53 "$SCOPE_DOMAIN_VAL" "$REGION" 2>/dev/null) || true
fi

if [ -n "$EXISTING_ALB" ]; then
log info "📝 Using ALB '$EXISTING_ALB' from Route53 record for $SCOPE_DOMAIN_VAL"
ALB_NAME="$EXISTING_ALB"
else
# Priority 2: If additional balancers configured, pick the least-loaded one
ADDITIONAL_BALANCERS=""
if [ "$INGRESS_VISIBILITY" = "internet-facing" ]; then
ADDITIONAL_BALANCERS=$(get_config_value \
--provider '.providers["scope-configurations"].networking.additional_public_balancers' \
--provider '.providers["container-orchestration"].balancer.additional_public_names' \
--default ""
)
if [ -n "$EXISTING_ALB" ]; then
log info "📝 Using ALB '$EXISTING_ALB' from Route53 record for $SCOPE_DOMAIN_VAL"
ALB_NAME="$EXISTING_ALB"
else
ADDITIONAL_BALANCERS=$(get_config_value \
--provider '.providers["scope-configurations"].networking.additional_private_balancers' \
--provider '.providers["container-orchestration"].balancer.additional_private_names' \
--default ""
)
fi
# Priority 2: If additional balancers configured, pick the least-loaded one
ADDITIONAL_BALANCERS=""
if [ "$INGRESS_VISIBILITY" = "internet-facing" ]; then
ADDITIONAL_BALANCERS=$(get_config_value \
--provider '.providers["scope-configurations"].networking.additional_public_balancers' \
--provider '.providers["container-orchestration"].balancer.additional_public_names' \
--default ""
)
else
ADDITIONAL_BALANCERS=$(get_config_value \
--provider '.providers["scope-configurations"].networking.additional_private_balancers' \
--provider '.providers["container-orchestration"].balancer.additional_private_names' \
--default ""
)
fi

if [ -n "$ADDITIONAL_BALANCERS" ] && [ "$ADDITIONAL_BALANCERS" != "null" ] && [ "$ADDITIONAL_BALANCERS" != "[]" ]; then
log debug "🔍 Additional balancers configured, resolving least-loaded ALB..."

if [ -n "$ADDITIONAL_BALANCERS" ] && [ "$ADDITIONAL_BALANCERS" != "null" ] && [ "$ADDITIONAL_BALANCERS" != "[]" ]; then
log debug "🔍 Additional balancers configured, resolving least-loaded ALB..."
CANDIDATES=$(echo "$ADDITIONAL_BALANCERS" | jq -r --arg base "$ALB_NAME" '[$base] + . | .[]')

CANDIDATES=$(echo "$ADDITIONAL_BALANCERS" | jq -r --arg base "$ALB_NAME" '[$base] + . | .[]')
log debug "📋 Candidate balancers: $(echo "$CANDIDATES" | paste -sd ',' - | sed 's/,/, /g')"

log debug "📋 Candidate balancers: $(echo "$CANDIDATES" | paste -sd ',' - | sed 's/,/, /g')"
MIN_RULES=-1
BEST_ALB="$ALB_NAME"

MIN_RULES=-1
BEST_ALB="$ALB_NAME"
for CANDIDATE in $CANDIDATES; do
RULE_COUNT=$(get_alb_rule_count "$CANDIDATE" 2>/dev/null) || {
log warn "⚠️ Could not query rules for ALB '$CANDIDATE', skipping"
continue
}

for CANDIDATE in $CANDIDATES; do
RULE_COUNT=$(get_alb_rule_count "$CANDIDATE" 2>/dev/null) || {
log warn "⚠️ Could not query rules for ALB '$CANDIDATE', skipping"
continue
}
log debug "📋 ALB '$CANDIDATE': $RULE_COUNT rules"

log debug "📋 ALB '$CANDIDATE': $RULE_COUNT rules"
if [ "$MIN_RULES" -eq -1 ] || [ "$RULE_COUNT" -lt "$MIN_RULES" ]; then
MIN_RULES=$RULE_COUNT
BEST_ALB="$CANDIDATE"
fi
done

if [ "$MIN_RULES" -eq -1 ] || [ "$RULE_COUNT" -lt "$MIN_RULES" ]; then
MIN_RULES=$RULE_COUNT
BEST_ALB="$CANDIDATE"
if [ "$BEST_ALB" != "$ALB_NAME" ]; then
log info "📝 Selected ALB '$BEST_ALB' ($MIN_RULES rules) over default '$ALB_NAME'"
fi
done

if [ "$BEST_ALB" != "$ALB_NAME" ]; then
log info "📝 Selected ALB '$BEST_ALB' ($MIN_RULES rules) over default '$ALB_NAME'"
ALB_NAME="$BEST_ALB"
fi

ALB_NAME="$BEST_ALB"
fi
else
log debug "📋 DNS type is '$DNS_TYPE', skipping Route53 lookup and load balancing"
fi

export ALB_NAME
Loading
Loading