Forum Discussion

boneyard's avatar
Mar 07, 2012

looking to optimize / generalize irule

i have an irule which selects a pool based on several known items (think: uri, client ip, port). i have many of these sets, so some strings and a poolname. currently this is all hard coded in the irule, which means many variables.

 

 

looking ahead this isnt a nice way to handle things and only becomes worse with every addition. id like to do this better and think data groups / classes can be a solution. (if there is an other one im open to it for sure).

 

 

i was thinking about having a data group per set of strings and pool. but that would mean having all the data group names hard coded in the irule right? is there some way to work around this? one thing i thought might work is having a "super" data group containing the names of the other data groups, would that work?

 

 

to look at it in another way: if i would do something like this in an other language i would use an array filled with arrays, but im not sure how to do it in an irule.

 

6 Replies

  • Hi Boneyard,

     

     

    How about having a set of data groups with one per component you're checking (URI, client IP, port, etc) and then have one set of these data groups per virtual server. You could then prefix the data groups using the virtual server name:

     

     

    vs1_uri_dg

     

    vs1_ip_dg

     

    vs1_port_dg

     

     

    vs2_uri_dg

     

    vs2_ip_dg

     

    vs2_port_dg

     

     

    You can get the current virtual server's name using [virtual name].

     

     

    Aaron
  • don't think i fully see the plan, are you suggesting something like below (i apologize for the bad pseudo code, dont have a f5 around now and removed a variable for keeping it small):

     

     

    class vs1_class {

     

    {

     

    "uri1"

     

    "45"

     

    "vs1_pool"

     

    }

     

    }

     

     

    class vs2_class {

     

    {

     

    "uri2"

     

    "465"

     

    "vs2_pool"

     

    }

     

    }

     

     

    if {[class match [string tolower [HTTP::uri]] equals [virtual name]_class AND [class match [TCP::local_port]] equals [virtual name]_class} {

     

    set pool some how

     

    }

     

     

    still have to figure something out for setting the pool.

     

     

    is there a way to control the element from a data group / class you want to compare? because above code would search through the whole data group / class i believe.

     

     

    something like this perhaps?

     

     

    class vs1_class {

     

    {

     

    "uri" {"uri1"}

     

    "port" {"45"}

     

    "pool" {"pool_vs1"}

     

    }

     

    }

     

     

    and then searching for uri and getting the value to compare or to set for pool? all depends on if the way to select a data group / class with [virtual name]_class works.

     

     

    and it depends on having a different virtual server for every set variables right?

     

  • I was thinking of having one set of data groups per virtual server. Maybe I've misunderstood your scenario. Can you clarify what logic you use to tie together the URIs, ports and pools?

     

     

    Aaron
  • checked the above and this indeed works.

     

    
    if { [class match -value ip equals [virtual name]_class] == [IP::client_addr] and [class match -value port equals [virtual name]_class] == [TCP::local_port]} {
      set pool [class match -value pool equals [virtual name]_class]
      log local0. "$pool"
      pool $pool
    }

     

    it just depends on having different virtual server names, would be nice to be independent of that. of course i can come up with some naming scheme that would allow this.

     

     

    still id like to try to keep it more generic, the general idea is that i have several sets of sets of variables to compare with the provided ones (via some method) and then select a pool.

     

     

    i don't need full code, just some pointers on how to handle this.
  • looked around some more and found an alternative which will do the trick i believe, would this be acceptable code or is there something to change / make better?

     

     

    please dont focus on the specifics, used variables might not make sense, it is the general idea.

     

    
    class all_app_classes {
      class_app1
      class_app2
    }
    
    class class_app1 {
    "ip" {"192.168.34.23"}
    "port" {"45"}
    "pool" {"pool_1"}
    } 
    
    class class_app2 {
    {
    "ip" {"192.145.224.23"}
    "port" {"55"}
    "pool" {"pool_2"}
    } 
    
      set id [class startsearch all_app_classes]
      while { [class anymore all_app_classes $id] } {
        set x [class nextelement all_app_classes $id]
        set app_class [lindex $x 0]
        log local0. "$app_class"
        
        if { [TCP::local_port] == [class match -value port equals $app_class] and [IP::client_addr] == [class match -value ip equals $app_class] } {
          log local0. "$app_class is the right class"
          set saved_class $app_class
        }
      }
    
      pool [class match -value pool equals $saved_class]
    
  • Yep, that seems like it should work in concept. Will you have multiple ip-port-pool combinations per application? If not, you could combine the data groups into one:

     

     

    app1 {"192.168.34.23 45 pool1"}

     

    app2 {"192.168.224.23 55 pool2"}

     

     

    Aaron