Created
June 7, 2012 16:07
-
-
Save nmische/2889692 to your computer and use it in GitHub Desktop.
iRule to allow clients to select a pool member based on a parameter set in the HTTP query string.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# irule_select_pool_member | |
# | |
# v1.0 - 7 June 2012 - nmische | |
# Rewritten from v0.2 at: https://devcentral.f5.com/wiki/irules.Select_pool_member_based_on_HTTP_query_string_parameter.ashx | |
# | |
# Purpose: | |
# Allows wharton wired clients to select a pool member based on a parameter set in the HTTP query string. | |
# | |
# Notes: | |
# Only works with pools with up to 9 members. Uses event command to disable all events so may not be safe to use with other iRules. | |
# | |
when RULE_INIT { | |
# Log debug info? 0 = no, 1 = yes | |
set static::log_debug 0 | |
# Name of the URI parameter name used to manually select a specific pool member | |
# Clients can append the member parameter to a query string in the format of: | |
# www.example.com/index.html?ltm_pool_member=2 | |
# where member is the parameter name | |
set static::member_param "ltm_pool_member" | |
} | |
when CLIENT_ACCEPTED priority 750 { | |
if { not [class match [IP::client_addr] equals datagroup_wharton_wired_subnets] }{ | |
event disable all | |
} | |
} | |
when HTTP_REQUEST { | |
# Track whether a member has been found in the query string or cookie | |
set member_num "" | |
# Check if query string contains "ltm_pool_member=" before evaluating the value | |
# Also check for a previously set cookie indicating a manually selected pool member. | |
if { [HTTP::query] contains $static::member_param or [HTTP::cookie $static::member_param] ne "" }{ | |
# Have the query string parameter take precedence over the cookie. | |
# So set the member_num based on the cookie and then overwrite it if the param value is set. | |
set cookie_val [HTTP::cookie $static::member_param] | |
set member_num $cookie_val | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Parsed member number from cookie: \$member_num: $member_num" } | |
# Parse the value of the parameter to get the pool member number being selected | |
# Use a workaround to handle a bug with URI::query, described in: | |
# CR137465: http://devcentral.f5.com/Default.aspx?tabid=53&forumid=5&tpage=1&view=topic&postid=1168257#1145270 | |
set query_val [URI::query "?&[HTTP::query]" "&${static::member_param}"] | |
if {$query_val ne ""}{ | |
set member_num $query_val | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Using member number from URI: \$member_num: $member_num" } | |
} | |
# If we have a member number then try to select a pool member | |
if { $member_num ne "" }{ | |
# Check member number value | |
switch -glob $member_num { | |
"0" { | |
# Exact match for 0 (client wants to clear cookie) | |
# Load balance the request and delete the cookie in the response | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Member 0 specified, will remove cookie in response." } | |
return | |
} | |
"[1-9]" { | |
# The parameter had a value between 1 and 9 | |
# Use lindex to get the nth -1 pool member "IP port" (lindex is 0 based) | |
# Use scan to parse the IP and port to separate variables (the pool command doesn't seem to handle them together) | |
# Use catch to handle any errors trying to parse the pool member | |
if { [catch {scan [lindex [lsort [members -list [LB::server pool]]] [expr {$member_num - 1}]] {%[^ ] %d} ip port} result] }{ | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Error parsing pool member from $member_num" } | |
} elseif { $result == 2 }{ | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Parsed IP port: $ip $port" } | |
# Use catch to handle any errors trying to select the pool member | |
if { not [catch {pool [LB::server pool] member $ip $port}] }{ | |
# Selecting pool member succeeded so exit this event of this iRule | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Successfully selected: $ip $port" } | |
return | |
} | |
} | |
} | |
} | |
} | |
# If we're still in the iRule there was no match or there were errors trying to select the pool member | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: No/invalid member_num parsed, load balancing request" } | |
event disable all | |
} | |
} | |
when HTTP_RESPONSE { | |
# Check if $member_num has a value | |
if { $member_num ne "" }{ | |
if { $member_num eq 0 } { | |
# Expire the cookie by inserting the name/value with an expire time in the past | |
HTTP::cookie insert name $static::member_param value $cookie_val path "/" | |
HTTP::cookie expires $static::member_param 0 absolute | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Expiring cookie $static::member_param=$cookie_val" } | |
} elseif { $cookie_val ne $member_num }{ | |
# Set a cookie with the member_num value | |
HTTP::cookie insert name $static::member_param value $member_num path "/" | |
if { $static::log_debug }{ log local0. "[IP::client_addr]:[TCP::client_port]: Inserting cookie $static::member_param=$member_num" } | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment