Forum Discussion

FishNiX_29746's avatar
FishNiX_29746
Icon for Nimbostratus rankNimbostratus
Jan 25, 2010

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....

 

7 Replies

  • 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
  • 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
  • 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 
             }   
           }   
         }   
       }   
     }   
     
  • 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 
     

  • 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
  •  

    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!

     

     

     

  • In that case I think your code closely matches to what you want.

     

     

    Bhattman