For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

avinashc's avatar
avinashc
Icon for Nimbostratus rankNimbostratus
Feb 25, 2025

F5 irule for multi-pool base on http_response

I have an iRule that distributes traffic between two different pools based on weights defined in data groups. If the application in one pool is down, it receives a 503 response, allowing the traffic to be forwarded to the other pool. This functionality is working as expected. However, when this situation occurs, the browser briefly displays a "page can't be reached" error before retrying and successfully loading the page. I want the iRule to attempt both pools before displaying an error to the user.

 

 

when CLIENT_ACCEPTED {
    # Initialize variables
    set ab_class "/imc/Shared/vs_lb_svc_kube_system_f5_nginx_deployment_dg"
    set ab_rule [class match -value "/" equals $ab_class]
    set retries 0
    set request_headers ""
    set pool_list [list]
    set active_pool ""

    # Populate the pool list and determine the active pool
    if {$ab_rule != ""} then {
        set service_rules [split $ab_rule ";"]
        foreach service_rule $service_rules {
            set fields [split $service_rule ","]
            set pool_name [lindex $fields 0]
            lappend pool_list $pool_name
            if { [active_members $pool_name] >= 1 } {
                set active_pool $pool_name
            }
        }
    }

    # Select the initial pool based on weights
    if {$ab_rule != ""} then {
        set weight_selection [expr {rand()}]
        foreach service_rule $service_rules {
            set fields [split $service_rule ","]
            set pool_name [lindex $fields 0]
            set weight [expr {double([lindex $fields 1])}]
            if {$weight_selection <= $weight} then {
                # Check if active pool members are available
                if { [active_members $pool_name] >= 1 } {
                    pool $pool_name
                    return
                } else {
                    # Select other pool with active members
                    if {$active_pool != ""} then {
                        pool $active_pool
                        return
                    }
                }
            }
        }
    }

    # If no active pool members are found, return a 503 (Service Unavailable)
    if {$active_pool == ""} then {
        TCP::respond 503
        return
    }
}

when HTTP_REQUEST {
    # Save the request headers if it is a GET request and not a retried request
    if { [HTTP::method] eq "GET" && $retries == 0 } {
        set request_headers [HTTP::request]
        log local0. "Saving HTTP request headers: $request_headers"
    }
}

when HTTP_RESPONSE {
    # Check if we got a 503 response
    if { [HTTP::status] == 503 } {
        # Log the 503 response for debugging purposes
        log local0. "Received 503 response, retrying request with next pool"

        # Increment the retry counter
        incr retries

        # Get the current pool
        set current_pool [LB::server pool]

        # Find the next pool in the list
        set next_pool ""
        foreach pool $pool_list {
            if { $pool == $current_pool } {
                continue
            }
            if { [active_members $pool] >= 1 } {
                set next_pool $pool
                break
            }
        }

        # If a next pool is found, retry the request with the next pool
        if { $next_pool != "" } {
            log local0. "Retrying with next pool: $next_pool"
            pool $next_pool
            HTTP::retry $request_headers
        } else {
            log local0. "No next pool found, responding with 503"
            TCP::respond 503
        }
    }
}

1 Reply