Forum Discussion

Jo_Anglin_5148's avatar
Jo_Anglin_5148
Historic F5 Account
Jan 15, 2009

uri redirect

I am a newbie to irule and would like some assistance in setting up an irule.

 

Currently I have a VS with a pool with 5 pool members and I am trying to set up an irule with will allow each client depending on their uri to access content on different servers.

 

 

amrvweb04 {

 

/7.2/*

 

/72Salesdemo/*

 

/PURV14944/*

 

/ops*

 

}

 

amrvweb03 {

 

/72Demo/*

 

/72dev/*

 

/PURV144945/*

 

/PURV161183/*

 

/PURV950053/*

 

/RV102535/*

 

/v72/*

 

/xRV950002/*

 

}

 

amrvweb01 {

 

/AUMON/*

 

/PURV154230/*

 

/RV648689/*

 

/RV900283DP/*

 

/RV910097/*

 

/RV950010/*

 

/RV950046/*

 

/RV950072/*

 

/RV950074/*

 

/RV950075/*

 

/RV950076/*

 

/MAINT/*

 

/nuTest/*

 

/nuTESTRS/*

 

/PURV144944/*

 

/PURV550587/*

 

/purv950058/*

 

/purv950056M/*

 

/RV100069/*

 

/RV144991/*

 

/RV154329/*

 

/RV161292/*

 

/RV161293/*

 

/rv550587/*

 

/rv648331/*

 

/rv648340/*

 

/rv651499/*

 

/rv900283/*

 

/RV950049/*

 

/rv950062/*

 

/rv950064/*

 

/RV950066/*

 

/RV950068/*

 

/RV950070/*

 

/RV950071/*

 

}

 

amrvweb05 {

 

/nosso/*

 

/xRV144991/*

 

}

 

amatlvsi03 {

 

/5.2_rv950007/*

 

/5._RV950048/*

 

/dev_5.2/*

 

}

 

 

 

when HTTP_REQUEST {

 

if {[matchclass [HTTP::uri] contains $::amrvweb04] } {

 

node 66.33.17.7

 

} else {

 

if { [matchclass [HTTP::uri] contains $::amrvweb03] } {

 

node 66.33.17.8

 

} else {

 

if { [matchclass [HTTP::uri] contains $::amrvweb01] } {

 

node 66.33.14.9

 

} else {

 

if { [matchclass [HTTP::uri] contains $::amrvweb05] } {

 

node 66.33.14.10

 

} else {

 

if { [matchclass [HTTP::uri] contains $::amatlvsi03] } {

 

node 66.33.14.11

 

} else {

 

node 66.33.14.12

 

}

 

}

 

}

 

}

 

}

 

}

 

 

 

Any pointers?

10 Replies

  • a couple things...

    you could consolidate into one class by mapping each uri to the appropriate node:

    consolidated_class {

    "/nosso/* 66.33.14.10"

    "/xRV144991/* 66.33.14.10"

    "/5.2_rv950007/* 66.33.14.11"

    "/5._RV950048/* 66.33.14.11"

    "/dev_5.2/* 66.33.14.11"

    }

    then your rule is reduced to:

     
     when HTTP_REQUEST { 
       if { [matchclass [string tolower [HTTP::uri]] contains $::consolidated_class] } { 
         pool myPool member [findclass [string tolower [HTTP::uri]] $::consolidated_class " "] port myPort 
       } 
     } 
     

    You'll note that I moved your example away from the node command and instead used the pool command. THis is important if you want the statistics at the pool level. This is untested, I don't have a resource right now, but should get you going.
  • I should also note that with this rule, you can specify the default node in an isolated pool with only member 66.33.14.12 and attach it to the virtual, that way it gets all the traffic not matched by the above rule. You could also add an else statement...
  • Jo_Anglin_5148's avatar
    Jo_Anglin_5148
    Historic F5 Account
    So we have a datagroup called LB_test_data_group which contains

     

    "/RCLweb1/ 66.31.13.45"

     

     

    Then we applied the irule:

     

    when HTTP_REQUEST { if { [matchclass [string tolower [HTTP::uri]] contains $::LB_test_data_group] } { pool LB_test_web_pool member [findclass [string tolower [HTTP::uri]] $:: "LB_test_data_group "] port myPort } else pool LB_pool_web_default } }

     

     

    We were not able to pull up a webpage for the uri specified.

     

     

    What am I missing?
  • Deb_Allen_18's avatar
    Deb_Allen_18
    Historic F5 Account
    Matchclass matches on the whole class entry, not just the first field, so you can't use matchclass with the suggested consolidated class. For this approach to work, you will need to have 2 classes, one for matching, another for grabbing the related pool:

     

       
       class UriMatch {    
         "nosso"    
         "xRV144991"    
         "5.2_rv950007"    
         "5._RV950048"    
         "dev_5.2"    
       }    
          
       class DestMap {    
         "nosso 66.33.14.10"    
         "xRV144991 66.33.14.10"    
         "5.2_rv950007 66.33.14.11"    
         "5._RV950048 66.33.14.11"    
         "dev_5.2 66.33.14.11"    
       }    
       

     

    Then you can use the matchclass command using the first class to condition a findclass lookup in the second.

     

     

    Definitely you need to delete the the trailing * in the UriMatch class entries. That would be necessary in any case since matchclass performs a literal string match, no wildcards. The starts_with operator can be used to emulate a trailing wildcard. However, since we can just pull the first directory (looks like all but ops*) to make the match, and we need a discrete value anyway for the lookup in the 2nd class (findclass doesn't support operators, rather makes full match against the first field), I'm going to suggest using the directory name only for both so it's a bit more intutive. Class values have been modified to match, and this code extracts the dir name:

     

       
       [getfield [string tolower [HTTP::uri]] "/" 2]   
       

     

     

    Resulting iRule looks like this:

     

    when HTTP_REQUEST {   
         set FirstDir [getfield [string tolower [HTTP::uri]] "/" 2]   
         if {[matchclass $FirstDir equals $::UriMatch]}{   
           pool myPool member [findclass $FirstDir $::DestMap " "]   
         }   
       }   
       

     

    The ops* case would need to be specifically handled, along with any other exceptions to the first-directory-match algorithm.

     

     

    If you vary the length of path you are matching on, you can get into a sticky wicket doing iterative matches, longest first, since you don't have the flexibility of specifying an operator & need to extract just that bit for the match. (I've done it, have the code somewhere, but it's far from optimal.) However, in this case since all of your conditions but one (/ops*) are matches of the first directory in the path, you can use getfield to extract just that first directory name.

     

     

    Def agree that pool command is better than node. Along those lines, it might make sense to build a pool for each server, even though they would only have a single member, rather than specifying a specific member of one pool. That way you can add redundancy later by just adding pool members. You'd just change the class to include the poolnames instead of IP's, then change the pool command to:
       
           pool [findclass $FirstDir $::DestMap " "]   
       

     

    hth

     

    /deb

     

     

    ps

     

    Look for major improvements to the class management commands in an upcoming release. Will make all this a walk in the park, comparatively speaking...
  • Deb_Allen_18's avatar
    Deb_Allen_18
    Historic F5 Account
    (hmmmm, anybody else find it exceedingly annoying that code blocks are not protected from smiley macro expansion...?)

     

     

    changed the name of the variable to something not starting with P...
  • Yes, definitely annoying...and thanks for picking up my scraps :-)
  • Jo_Anglin_5148's avatar
    Jo_Anglin_5148
    Historic F5 Account
    Thanks Deb. I will have this tested and let you know the results.

     

    The previous suggestion from Citizen_elah unfortunately didn't work but we appreciate his time and guidance.
  • Hi Deb,

     

     

    Could you exaplin this a bit more:

     

     

    If you vary the length of path you are matching on, you can get into a sticky wicket doing iterative matches, longest first, since you don't have the flexibility of specifying an operator & need to extract just that bit for the match.

     

     

    Thanks,

     

    Naman