Forum Discussion

Jason_Hook_4092's avatar
Icon for Nimbostratus rankNimbostratus
Feb 15, 2012

1 VS, 2 pool routing

I have the following iRule. It's working as needed. It might be clumbsy, but it works. (thoughts on a cleaner implementation?).



It chooses a pool based on a cookie, or a response from the server in the pool it it hit the wrong pool.



What I to add more pool-selection logic to it to choose a pool (after determining which client it is) based on URI in order to separate some apps from the rest due to performance/capacity concerns.



Thoughts on how I can accoplish this in the most effective/maintainable way?



I hope copy/paste looks ok, not sure how to paste 'code' and make it look pretty here:




set iRule priority higher than the default to better it's functionality


priority 300




Look for existing pool cookie otherwise determine where to go based on


a lookup of client IP in the Client 'proxy' Server addresses datalist




set to 1 to enable LTM logging, 0 to disable LTM logging


set debugWPPBF 0


init flag whether to run iRule or just exit


set ShouldExitWPPBF 0



if {[string tolower [HTTP::path]] starts_with "/streamer"} {


stop running the iRule since PERSIST profile will pick up /streamer calls


set ShouldExitWPPBF 1







if {$debugWPPBF}{log "Cookie TFPoolId Exists: [HTTP::cookie exists "TFPoolId"]"}



if {[HTTP::cookie exists "TFPoolId"] && ![info exists retriesWPPBF]} {


Pool cookie exists...just send the request


switch [HTTP::cookie "TFPoolId"] {


"1" { set PoolIdWPPBF "BLTCP_WEB" }


"2" { set PoolIdWPPBF "WSI_WEB" }


default { set PoolIdWPPBF "BLTCP_WEB" }




pool $PoolIdWPPBF


if {$debugWPPBF}{log "Cookie Pooling [IP::client_addr] to $PoolIdWPPBF"}


} else {


no pool cookie so we need to determine where to go


if { [info exists retriesWPPBF] } {


We are in retry so just send it to the new pool


if {$debugWPPBF}{log "isRetry to $NewPoolIdWPPBF"}


Update content length header with updated payload length


HTTP::header replace Content-Length [string length [HTTP::payload]]


pool $NewPoolIdWPPBF


} else {


we have no pool cookie and are in the 1st request...get setup to determine if we need to retry to a new pool


if {$debugWPPBF}{log "No Cookie"}


set noCookie 1


Set request, HTTP post header.


set requestWPPBF [HTTP::request]


if {$debugWPPBF}{log "HTTP::request: $requestWPPBF"}


Set payload content legth to capture.


if {[HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 4000000}{


set content_lengthWPPBF [HTTP::header "Content-Length"]


} else {


set content_lengthWPPBF 4000000




Capture HTTP payload from request, HTTP::collect triggers event HTTP_REQUEST_DATA


if { [info exists content_lengthWPPBF] && $content_lengthWPPBF > 0} {


if {$debugWPPBF}{log "Collecting Payload"}


HTTP::collect $content_lengthWPPBF




set PoolIdWPPBF ""


set isMatchWPPBF [class match [IP::client_addr] equals WFAPriceServerList]


if {$debugWPPBF}{log "Returned '$isMatchWPPBF' from WFA price server lookup"}


if {$isMatchWPPBF} {


pool WSI_WEB


if {$debugWPPBF}{log "Pooling to WSI_WEB"}


} else {




if {$debugWPPBF}{log "Pooling to BLTCP_WEB"}












Set payload, depends on HTTP::collect done in HTTP_REQUEST event.


set payloadWPPBF [HTTP::payload]



Append HTTP payload to HTTP request header to form a complete HTTP post request (request + payload)


append requestWPPBF [HTTP::payload [HTTP::payload length]]



Log payload


if {$debugWPPBF} { log "Payload: $payloadWPPBF - length: [HTTP::payload length]" }







Watch for a response status of 307 from a misdirected pool


and change the cookie value accordingly


otherwise set the cookie to the selected pool


if {$ShouldExitWPPBF} { return }


if {$debugWPPBF}{log "status: '[HTTP::status]' - header: '[HTTP::header "WMErrorID"]'"}


if {[HTTP::status] eq "307" && [HTTP::header "WMErrorID"] eq "307" } {


HTTP::cookie remove "TFPoolId"


if {[HTTP::header value "FirmRoute"] eq 901} {


set NewCookieValueWPPBF "2"


HTTP::cookie insert name "TFPoolId" value $NewCookieValueWPPBF path "/"


set NewPoolIdWPPBF "WSI_WEB"


if {$debugWPPBF}{log "Wrong Pool, Changing to WSI_WEB"}


} else {


set NewCookieValueWPPBF "1"


HTTP::cookie insert name "TFPoolId" value $NewCookieValueWPPBF path "/"




if {$debugWPPBF}{log "Wrong Pool, Changing to BLTCP_WEB"}





if { ![info exists retriesWPPBF] } {


Set retries to activate the retry logic


set retriesWPPBF 1


Retry HTTP request/payload to another pool.


if {[info exists requestWPPBF] && $requestWPPBF ne ""} {


if {$debugWPPBF}{log "Retrying: $requestWPPBF"}


HTTP::retry "$requestWPPBF"




} else {


if {$debugWPPBF}{log "No collected request - responding to client"}


HTTP::cookie remove "TFPoolId"






} else {


if {$debugWPPBF}{log "PoolIdWPPBF: $PoolIdWPPBF"}


if {[info exists noCookie] || [info exists retriesWPPBF]} {


switch [LB::server pool] {


"BLTCP_WEB" { HTTP::cookie insert name "TFPoolId" value "1" path "/" }


"WSI_WEB" { HTTP::cookie insert name "TFPoolId" value "2" path "/" }


default { HTTP::cookie insert name "TFPoolId" value "1" path "/" }




Update content length header with updated payload length


REMOVED HTTP::header replace Content-Length [string length [HTTP::payload]]


if {$debugWPPBF}{log "No 307, Setting Cookie for [LB::server pool] - Client: [IP::client_addr]"}


if {[info exists noCookie]}{ unset noCookie }




if {[info exists retriesWPPBF]}{


if {$debugWPPBF}{log "unsetting retriesWPPBF"}


unset retriesWPPBF






Insert header with responding server IP


HTTP::header replace "serverIP" [IP::server_addr]






if {$ShouldExitWPPBF} { return }


if { [info exists retriesWPPBF] } {


if {$debugWPPBF}{log "Redirecting Request to $NewPoolIdWPPBF - member: [LB::server]"}


LB::reselect pool $NewPoolIdWPPBF






3 Replies

  • what about if we create another HTTP_REQUEST event with higher priority and disable all event when the condition matches?



    event wiki

  • We have an n-tier application architecture. The web tier/pools are the entry point to the environment. The catch is that we have 2 production environments that reside behind the same VIP. Currently, one pool of web servers (PoolId=1) is for our web products as a service bureau offering...and the other pool (PoolId=2) is for one specific client that requires us to have a separate set of servers (pretty much a mirror of the architecture that is behind PoolId=1) so there is impact isolation (they are paying to have their own in order to not be impacted if another of our clients add load in the environment that slows it down).



    so, I have to still decide PoolId 1 or 2, but need to add additional logic to splid PoolId into more pools based on URI.



    1) Client A would route to PoolId 1 as a service bureau client, but they are accessing /appX so they need to be on service bureau side (PoolId=1) and then web pool 1B that contains /appX.



    2) Client A calls another application so they are routed to PoolId=1 again, but they are calling for /appZ which isn't defined to its own pool so it would be sent to the PoolId=1 default of web pool 1A



    3) Client B is the "special" client and will be routed to PoolId=2 and only has a subset of the applications that service bureau has so they just get routed to web pool 2A as the default.



    4) Client C is another service bureau client so they will route to PoolId=1 and then we need to check the /app? URI again to route to the correct PoolId=1 (service bureau n-tier stack) web pool.



    Make sense?



    At this time...there is no requirement to split another customer to their own set of servers (which would just be added as PoolId=3 if needed) so I'm not worried there.



    I have the PoolID 1 or 2 working...I am open to suggestions on bettering that iRule as-is, but I need to add the 2nd part where I route the request based on URI...AFTER I decide what stack (PoolID 1 or 2).



    I'm just not sure the "best" way to add this extra level of logic without making the iRule a sloppy mess of "if..then" or "switch" statements.



    Suggestions wanted...