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

Hank_Stallings's avatar
Hank_Stallings
Icon for Nimbostratus rankNimbostratus
Jul 29, 2013

Set Manual Cookie Peristence

I’m trying to implement an iRule from wiki article at:

 

https://devcentral.f5.com/wiki/irul...tence.ashx

 

I am pretty new at iRules and I’m missing something, so I apologize in advance for my ignorance.

 

I have the following setup:

 

Virtual Server vs_MyTwoServers

 

Default Pool Pool_MyTwoServers

 

Persistence Profile mySiteCookie Parent profile: cookie Cookie Method: Http Cookie Insert Cookie Name: PersistCookie8hrs

 

Nodes: 10.6.0.68:80 (Server7910) 10.6.0.68:80 (Server7911)

 

 

I want to be able to add a uri query of and have that session traffic only go to Server7910

 

 

I’ve setup a data group list called my_forced_nodes:

 

Data Group List Name: my_forced_nodes

 

Type: String

 

String Records:

 

7910 := 10.6.0.68 80

 

7911 := 10.6.0.69 80

 

 

iRule from wiki article with my information in it:

 

-----------------------------------------------------------------------------

 

when RULE_INIT {

 

set cookie_name "my_node_forced"

 

}

 

when HTTP_REQUEST {

 

Get node id from URL ending in ?node=server1, ?node=server2, etc.

 

set node_forced [findstr [HTTP::uri] "?node=" 6]

 

 

Or from previous cookie

 

set has_cookie [HTTP::cookie exists $::cookie_name]

 

 

if { $node_forced eq "" and $has_cookie } {

 

set node_forced [HTTP::cookie value $::cookie_name]

 

}

 

 

Map node id to IP and port found in a class

 

Entries should be strings of the form

 

 

 

if { $node_forced ne "" } {

 

set node_data [findclass $node_forced $::my_forced_nodes " "]

 

if { $node_data ne "" } {

 

set node_ip [getfield $node_data " " 1]

 

set node_port [getfield $node_data " " 2]

 

pool Pool_MyTwoServers member $node_ip $node_port

 

} else {

 

set node_forced ""

 

}

 

}

 

}

 

when HTTP_RESPONSE {

 

if { $node_forced ne "" } {

 

Add a cookie to continue forcing node assignment

 

HTTP::cookie insert name $::cookie_name value $node_forced path "/"

 

}

 

elseif { $has_cookie } {

 

Delete cookie and resume load balancing (with built-in persistence)

 

HTTP::cookie insert name $::cookie_name value "" path "/"

 

HTTP::cookie expires $::cookie_name 0 absolute

 

}

 

}

 

4 Replies

  • Updated for v10/11 with minor changes:

    
    when RULE_INIT {
    set static::cookie_name "my_node_forced"
    }
    when HTTP_REQUEST {
     Get node id from URL ending in ?node=server1, ?node=server2, etc.
    set node_forced [findstr [HTTP::query] "node=" 5]
    
     Or from previous cookie
    set has_cookie [HTTP::cookie exists $static::cookie_name]
    
     If node_forced (from query) isn't there but cookie exists - set node_forced = cookie value
    if { $node_forced eq "" and $has_cookie } {
    set node_forced [HTTP::cookie value $static::cookie_name]
    }
    
     If node_forced (from query) is there but cookie is not - set cookie flag
    if { $node_forced ne "" and !$has_cookie } {
    set do_cookie 1
    }
    
     Map node id to IP and port found in a class
    if { $node_forced ne "" } {
    set node_data [class match -value $node_forced equals my_forced_nodes]
    if { $node_data ne "" } {
    set node_ip [getfield $node_data " " 1]
    set node_port [getfield $node_data " " 2]
    pool local-pool member $node_ip $node_port
    } 
    } 
    }
    when HTTP_RESPONSE {
    if { [info exists do_cookie] } {
    unset do_cookie
     Add a cookie to continue forcing node assignment
    HTTP::cookie insert name $static::cookie_name value $node_forced path "/"
    } 
    }
    

  • Thanks Kevin!! It appears to be consistently working.

     

     

    Appreciate your help!

     

     

    Hank
  • Add on to this question:

     

    Can you dynamically build a data group list by querying a pool for a list of nodes? For instance in the example above, can an iRule determine the number of servers in the pool and assign a numeric value to the node member? Then instead of using uri query of node=7910, it could be node=1?

     

     

    What I'm trying to get at is, can the iRule be generic that it would work for any VIP/Pool to be enable app owners to test each individual node without having to create a data group list and an iRule for each application.

     

     

    Thanks,

     

     

    Hank
  • Here's a minor modification of the above using a dynamically created list on CLIENT_ACCEPTED:

    
    when RULE_INIT {
    set static::cookie_name "my_node_forced"
    }
    when CLIENT_ACCEPTED {
     create simple pool member list
    set my_nodes [members -list local-pool]
    }
    when HTTP_REQUEST {
     Get node id from URL ending in ?node=server1, ?node=server2, etc.
    set node_forced [findstr [HTTP::query] "node=" 5]
    
     Or from previous cookie
    set has_cookie [HTTP::cookie exists $static::cookie_name]
    
     If node_forced (from query) isn't there but cookie exists - set node_forced = cookie value
    if { $node_forced eq "" and $has_cookie } {
    set node_forced [HTTP::cookie value $static::cookie_name]
    }
    
     If node_forced (from query) is there but cookie is not - set cookie flag
    if { $node_forced ne "" and !$has_cookie } {
    set do_cookie 1
    }
    
     Map node id to IP and port found in a class
    if { $node_forced ne "" } {
    set node_data [lindex $my_nodes $node_forced]
    if { $node_data ne "" } {
    set node_ip [getfield $node_data " " 1]
    set node_port [getfield $node_data " " 2]
    pool local-pool member $node_ip $node_port
    } 
    } 
    }
    when HTTP_RESPONSE {
    if { [info exists do_cookie] } {
    unset do_cookie
     Add a cookie to continue forcing node assignment
    HTTP::cookie insert name $static::cookie_name value $node_forced path "/"
    } 
    }
    

    Essentially the same as before, but this time a list is created dynamically of all of the pool members (set my_nodes [members -list local-pool]). Use set my_nodes [active_members -list local-pool] to get a list of only the available nodes. Then later just read that list entry to get the desired node (set node_data [lindex $my_nodes $node_forced]).

    An alternative method would be to modify the data group via shell script and TMSH commands on some specified interval. Create an external monitor that polls the pool members, rewrites the data group, then updates it in the config. Add this monitor to a "phantom pool" - a pool not tied to a virtual server. This method allows you to create a scheduled job that is backed up as part of the config.