Forum Discussion

Brad_Baker's avatar
Aug 11, 2016

Persist based on query string

Our QA team needs a way to specify a backend node via a query string and have all subsequent queries persist to that node for testing purposes.

I have written the following irule which send the request to a specified node - the problem is that associated requests to things like images, javascript, style sheets don't match the irule and thus get sent to a random backend web server:

 DESCRIPTION:
 This if the URI contains a query parameter named server this irule attempts
 to match the server name to a datagroup named servername2ip_datagroup and
 use that to send the user to the appropriate back end server. 

 1) This rule relies on the servername2ip_datagroup datagroup. Which is a
 server name to IP datagroup on the load balancer. This needs to be maintained
 / updated as server IPs or names change.


when HTTP_REQUEST { 
 If the uri contains a query parameter named server
if { [HTTP::uri] contains "server" } {
     Define a lowercase variable to store the server name
    set webserver [URI::query [string tolower [HTTP::uri]] server]

     Define a variable to store the port to make this rule https/http agnostic
    set prt [TCP::local_port]

     If the server query parameter matches an entry in the datagroup
    if { [class match $webserver equals servername2ip_datagroup] } {

         Direct traffic to that node.
        node [class lookup $webserver servername2ip_datagroup] $prt

        }
    }
}

I think perhaps I need to add persistence after: node [class lookup $webserver servername2ip_datagroup] $prt

I tried adding persist source_addr 1800

But that's not working. Can any irule guru's out there help me get this working. Is persistence what I need - if so what's wrong with how I'm using it?

Thanks Brad

  • Your iRule seems to be just performing a load balancing decision and not persisting. So, you can use something like this:

    when HTTP_REQUEST { 
     If the uri contains a query parameter named server
    if { [HTTP::uri] contains "server" } {
         Define a lowercase variable to store the server name
        set webserver [URI::query [HTTP::uri]]
         If the server query parameter matches an entry in the datagroup
        if { [class match $webserver equals servername2ip_datagroup] } {
            pool POOL_WITH_NODE
            }
        }
    }
    
  • If you are trying to persist based off of a string use a line similar to this, the value after the variable is how long the persisted string should remain in the UIE table.

     

    persist uie $variable 518400

     

  • This sort of seems to be working:

             Direct traffic to that node.
            pool [LB::server pool] member [class lookup $webserver servername2ip_datagroup] $prt
            persist uie $webserver 518400
    

    The first request for index.php goes to the correct node, whereas the resources (css, js, images) go to a random backend server. If I refresh the page though all requests seem to go to the correct server.

    I don't suppose there's a way to make it work consistently for the very first request?

  • You don't need persistence, if you are selecting a pool member based on the query string value. I misunderstood your initial request.

    I am assuming, you are sending it to port 80 on the pool member and this could work:

    when HTTP_REQUEST {
        if { [HTTP::uri] contains "server" } {
        set query_value [URI::query [string tolower [HTTP::uri]] server]
        pool [LB::server pool] [member $query_value 80]
    }
    }
    
  • You're right that persistence doesn't seem to be required for this to work but the issue I mention above still exists. So for example:

    1st Request

     URL: index.php?server=web-server1
    
     Resource: index.php
     Served by: web-server1
    
     Resource: mylogo.jpg
     Served by: web-server2
    
     Resource: index.css
     Served by: web-server2
    

    2st Request and subsequent requests (refresh)

     URL: index.php?server=web-server1
    
     Resource: index.php
     Served by: web-server1
    
     Resource: mylogo.jpg
     Served by: web-server1
    
     Resource: index.css
     Served by: web-server1
    

    I'm assuming this behavior is perhaps due to chrome and other browsers making parallel requests and thus even though I've set a pool member it doesn't honor it for all requests until I refresh a second time? If so I'm wondering if that's avoidable anyway?