Technical Articles
F5 SMEs share good practice.
cancel
Showing results for 
Search instead for 
Did you mean: 
Deb_Allen_18
Historic F5 Account

A very common use of iRules is to choose an appropriate destination based on the current traffic or request details. In this article I'll review the iRules commands you should have in your repertoire for selecting the right pool, pool member or destination address under specific conditions. Other articles in the series: 


Selecting a destination

Command: pool

In most cases, the destination you want to specify is a just a specific pool of servers serving the same content.

The command to choose a pool is simply "pool":

 

pool <poolname>


You can either specify a literal pool name:

pool HTTP_pool


or use a variable to specify one:

pool $myPool


You can also choose a specific pool member using the pool command:

pool HTTP_pool member 10.10.10.1 80


Command: node

The "node" command is useful if you want to send traffic to a specific IP/port combination that is not defined as a pool member:

when HTTP_REQUEST {
  if { [HTTP::uri] starts_with "/admin" } {
    node 10.1.1.200 8080
  } else {
    pool HTTP_pool
  }
}


When is the "default pool" not the default pool?

When configuring a standard virtual server, you can specify a default pool and/or any number of iRules as resources for the virtual server. iRules applied to the virtual may or may not select a pool or pool member. If not, the default pool configured on the virtual server will be used for all traffic. If the iRule does select a pool for a connection or request, the selected pool (rather than the configured default pool) then becomes the default pool for the remainder of that connection unless another pool is specifically selected. That's important to remember for transaction-based protocols such as HTTP for which traffic is often split per request.

Consider the following example (simplified for demonstration purposes):

A single keepalive HTTP connection to the virtual server is established.
The first HTTP request on that connection is for an HTML page, then several subsequent requests are made for graphics and stylesheets, then another HTML page, then more graphics, etc.

HTML pages are hosted on one set of servers, graphics on another, and style sheets on a third set. The virtual server configuration includes html_pool as the default pool, and the following iRule to distribute traffic to each pool based on content:

when HTTP_REQUEST {
  switch -glob [HTTP::path] {
    *.css { pool css_pool }
    *.jpg { pool jpg_pool }
  }
}


Here's is the breakdown of where traffic would be sent using this iRule:

index.html - - >html_pool
logo.jpg - - >jpg_pool
style.css - - >css_pool
page2.html - - >css_pool
logo2.jpg - - >jpg_pool
style2.css - - >css_pool


Notice anything odd?
The request for page2.html didn't go to the configured default pool "html_pool".  Because no pool selection condition matched that request, it followed the last request made on that connection to "css_pool" (which most likely resulted in a 404 "Not Found" error, and the supporting css & image that page would have called would never be requested.)

A simple addition to the iRule is all that is required to enforce the desired "default" pool for all requests not matching *.css or *.jpg:

when HTTP_REQUEST {
  switch -glob [HTTP::path] {
    *.css { pool css_pool }
    *.jpg { pool jpg_pool }
    default { pool html_pool }
  }
}


If you're using" if / elseif / else" instead of "switch", you can do the same by specifying the default pool in the final "else" clause:

when HTTP_REQUEST {
  if { [HTTP::path] ends_with "*.css" }{
    pool css_pool
  } elseif { [HTTP::path] ends_with "*.jpg" }{
    pool jpg_pool
  } else {
    pool html_pool
  }
}


Multiple pool selections

In BIG-IP v4.x, iRule processing ended when you chose a pool.
That's no longer true in LTM 9.x: You can choose a target destination at any of several decision points, and the last one selected will be the one to which the traffic is sent.

Checking destination status before sending traffic

There are a couple of iRules commands you can use to check the status of the destination before sending traffic. (Note: Application health monitors capable of accurately determining the health of the load balanced service must be applied to the pool members before these commands will return actual server status.)

Command: active_members

Before sending traffic to a pool, you might want to check if the pool has any members available. You can do that with the "active_members" command, and if the pool has no active members:

when CLIENT_ACCEPTED {
  if {[active_members PoolHTTPS] < 1}{
    SSL::disable
    reject
  } else {
    pool PoolHTTPS
}


Command: LB::status

Before sending traffic to a specific pool member, you can use the "LB::status" command to verify it is available for load balancing, and if not, take an alternative action:

when HTTP_REQUEST {
  set pserver [persist lookup uie [HTTP::cookie PersistCookie]] 
  if { [LB::status pool http_pool member $pserver 80] eq "up" } {
    pool http_pool member $pserver 80
  } else {
    log "Persist server $pserver:80 down! Redirecting"
    HTTP::redirect "http://server.domain.com/BrokenPersistence.html"
  }
}

(Note: LB::status was added in LTM 9.2.0, and backported to 9.1.2 HF4)

Catching destination failures after sending traffic

If your iRule chooses a pool or member without checking the status first or if you use the node command to send traffic to an unmonitored destination, the selected destination may not be available to service the request. In that case, the LB_FAILED event will be triggered, and you can include logic in your iRule to handle such circumstances.

Here's a modification of an example I used earlier which uses LB_FAILED to specify fallback logic when the admin server fails to respond:

when HTTP_REQUEST {
  if { [HTTP::uri] starts_with "/admin" } {
    set admin 1
    node 10.1.1.200 8080
  } else {
    set admin 0
    pool HTTP_pool
  }
}
when LB_FAILED {
  switch $admin {
    1 {
      log local0. "Admin server 10.1.1.200:8080 not responding"
      node 10.1.1.201 8080
    }
    2 {
      log local0. "Admin server 10.1.1.201:8080 not responding"
      node 10.1.1.202 8080
    }
    3 {
      log local0. "Admin server 10.1.1.202:8080 not responding"
      reject
    }
  }
  incr admin
}
Comments
brad_11480
Nimbostratus
Nimbostratus
When an iRule slects a pool so the default pool is not used for the remainder of the connection, what role does any persistence play in the selection of the pool member?

 

 

My iRule specifes a pool but not a specific member. I don't need any persistence on this 'override' since it serves static content on a per request basis. The persistence set for the virtual server is intended for the default pool, which is a set of weblogic servers where a session must be maintained.

 

 

It appears that there is persistence being applied (the virtual server has cookie insert). if so, how does it determine persistence association to each pool I could be selecting?

 

 

Thanks.

 

 

Deb_Allen_18
Historic F5 Account
I think this might answer your question:

 

AskF5 SOL9815: Using an iRule to select among pools may cause cookie persistence failure

 

https://support.f5.com/kb/en-us/solutions/public/9000/800/sol9815.html
brad_11480
Nimbostratus
Nimbostratus
Yes, that does help explain what appears to be occuring and I went back and checked the cookies being set for this session and I see there are two-- one for the default pool and one for the static content, both using the BigIP default naming which uses the pool name.

 

 

the virtual server has a persistence method defined. can I 'cancel' it when i am working with the static pool? would iRule such as the fragment below continue with persistence for the vitual server default pool selection except when a different pool is selected and a 'persist none' is used?

 

 

if {$target starts_with "pool"_} {

 

pool $target

 

persist none

 

}

 

 

thanks..
Deb_Allen_18
Historic F5 Account
sounds like that would work.
Peter_Z
Cirrus
Cirrus

I used to use the command "pool" or "pool <pool_name> member" in past to select pool or specific member from an iRule and I've noticed the following random behavior:

  • when calling pool in custom partition from iRule in the same partition, it's required to use full path/name of the pool, otherwise it may work randomly or work for a few days and then suddenly it stops with the TCL error in the logs saying it can't find the pool. To avoid this behavior an iRule /mypartition/irule should call the pool as /mypartition/pool1
  • similar setup doesn't work for me when I try to call specific member. calling it with either of the ways below ends up with the TCL error saying it can't find a pool member:

 

pool pool1 member 10.10.10.10 8080

pool /mypartitino/pool1 member 10.10.10.10 8080

 

this problem doesn't occur when the irule and pool is in partiion /Common/ and you omit the partition name when calling the pool

 

Any Idea how to fix it?

When you check the bigip.conf file you can see that every object is in fact preceded with partiion name, e.g. ltm pool /mypartition/pool1 even individual pool members within the pool:

 

ltm pool /mypartition/pool1{

  load-balancing-mode least-connections-member

  members {

    /mypartition/10.10.10.10:80 {

      address 10.10.10.10

 

however you can't specify the member in the irule with preceding partition name - it fails with syntax error expecting IP address only:

 

pool /mypartition/pool1 member /mypartition/10.10.10.10 8080

 

omitting the partition name still results in TCP error saying it can't find the pool member:

 

pool /mypartition/pool1 member 10.10.10.10 8080

 

Kiran_Kumar
Nimbostratus
Nimbostratus

Anyone has an idea for below requirement.

vip with 2 pools. Need to select primary pool if active members is greater than 10% of total pool members

Else, select secondary pool.

if both pools have less than 10% active members, then default to primary pool

@Deb_Allen_18 @Peter_Z  @brad_11480  or anyone

Version history
Last update:
‎23-Nov-2007 16:00
Updated by:
Contributors