Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

HOST/URI to pool mapping via iRule and class and trailing /

Greetings -

I'm attempting to write a generic iRule to send traffic for a URI to a specific pool. I will use this over "many" virtuals with "many" URIs.

I've chosen to use a class to store the mappings:

  
class host_uri_pool_selector_class {
"docs.foobar.edu /foo/ opa_pool"
"docs.foobar.edu /foobar/ baz_pool"
"test.foobar.edu /bar/ bar_pool"
}

rule set_pool_by_host_and_uri {
when HTTP_REQUEST {
foreach row $::host_uri_pool_selector_class {
if { [string tolower [HTTP::host]] equals [getfield $row " " 1] }{
if { [string tolower [HTTP::uri]] starts_with [getfield $row " " 2] }{
pool [getfield $row " " 3]
}
}
}
}
}



What's the most efficient way to check for the / at the end of each URI so that /foo and /foobar are not matched by whichever hits first but the URI still works in a browser without the trailing /?

Any other easy way to do this? I want people to easily be able to modify the class and to have a central location for this data. Can I use findclass or matchclass to make this faster?


EDIT: sorry about the blockquote, hopefully code tags will fix it....
0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Hi FishNiX,
I think you might be able speed things up if you avoid using the FOR loop


 
class host_uri_pool_selector_class {
"docs.foobar.edu /foo/ opa_pool"
"docs.foobar.edu /foobar/ baz_pool"
"test.foobar.edu /bar/ bar_pool"
}

rule set_pool_by_host_and_uri {
when HTTP_REQUEST {
set row [findclass [string tolower[HTTP::host]] $::host_uri_selector_class
if { [string tolower [HTTP::host]] equals [getfield $row " " 1] } {
if { [string tolower [HTTP::uri]] starts_with [getfield $row " " 2] } {
pool [getfield $row " " 3]
}
}
unset row
}
}



I hope this helps

#Bhattman
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
It sounds like FishNiX wants to get the longest match though. You could loop through the class row by row and track the curent longest match of the host and URI until you get through all rows. Or another option would be to combine the first two columns of the class and then use lindex -index -descending to sort the class as a list. This would probably only work in 9.x though, as you can't access a datagroup/class as a standard TCL list in 10.x.

Here is a rough example of the second option for 9.x:

 
when HTTP_REQUEST {

# Class order isn't guaranteed to come back in the order entered in the bigip.conf...
log local0. "list: $::host_uri_pool_selector_class"
log local0. "lsort: [lsort -decreasing -index 0 $::hooleya_host_uri_pool_selector_class]"

# Sort the datagroup on the first field, with longest lengths first
foreach row [lsort -decreasing -index 0 $::host_uri_pool_selector_class] {
log local0. "\$row: $row"
if {[string tolower [HTTP::host]][HTTP::uri]] starts_with [getfield $row " " 1]}{
log local0. "Found longest match: $line; pool: [getfield $row " " 2]"
break
}
}
}


For an example of manually tracking the longest match, you can use Deb's example below. This example would also work with the class command in v10.

http://devcentral.f5.com/wiki/default.aspx/iRules/FindclassAgainstVariableLengthURI.html
http://devcentral.f5.com/wiki/default.aspx/iRules/class

Aaron
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Thanks for your replies!

I hadn't really thought about it being the longest match...

I've been thinking about it as the most exact match of the first two entries in the class. Both HTTP::host and HTTP::uri need to match "the most" and if I ensure it ends with a "/" it will always work (as long as we never try to match /foo/foo.jsp I suppose).... maybe "longest" is the more correct way.

We are running 9.x. I don't really want the longest URL, I think I want the longest matching URI for whatver host is being requested....

What about something like this:

 
rule set_pool_by_host_and_uri {
when HTTP_REQUEST {
# Class order isn't guaranteed to come back in the order entered in the bigip.conf...
log local0. "list: $::host_uri_pool_selector_class"
log local0. "lsort: [lsort -decreasing -index 0 $::host_uri_pool_selector_class]"

foreach row [lsort -decreasing -index 1 $::host_uri_pool_selector_class] {
log local0. "\$row: $row"
if { [string tolower [HTTP::host]] equals [getfield $row " " 1] }{
if { [string tolower [HTTP::uri]] starts_with [getfield $row " " 2] }{
pool [getfield $row " " 3]
break
}
}
}
}
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Also --

Will this work if there are multiple entries for the HTTP::host in the class? I think it will only return the first row found right?

 
set row [findclass [string tolower[HTTP::host]] $::host_uri_selector_class

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Posted By FishNiX on 01/26/2010 7:13 AM

Also --

Will this work if there are multiple entries for the HTTP::host in the class? I think it will only return the first row found right?

  
set row [findclass [string tolower[HTTP::host]] $::host_uri_selector_class




Yes findclass will search the class object and find a match and then return the row on that match to the variable "row"

#Bhattman
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Bhattman -

I understand, but wont it only return 1 row (the first it finds)? I'm my case, I could have many rows with the same HTTP::host.

Thanks!


0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
In that case I think your code closely matches to what you want.

#Bhattman

0