Forum Discussion

Devlin_T_149357's avatar
Oct 01, 2018

Help with iRule

Hi everyone

I'm trying to unpick someone elses iRule but failing miserably. From what I can tell this seems to be a very long winded way to essentially read the requested URI of a request, and match that to a value in a DGL (the "uriPoolMapClass" variable below). However, I cannot be certain and wondered whether someone here - a dab hand in iRuleology, could provide some insight?

Thank you.

when HTTP_REQUEST priority 100 {
    set poolId [string range [HTTP::uri] 1 [expr [string first "/" [HTTP::uri] 1]-1]]
    set poolIdLen [string length $poolId]
    set newUri "[string range [HTTP::uri] [expr $poolIdLen+1] end]"
    set uriPoolMapClass "[string range [virtual name] 0 end-2]uri_pool_map_class"
    set dstPool [class lookup [string tolower $poolId] $uriPoolMapClass]
    if {$dstPool ne ""} {
         Hash out next line to disable logging
         log local0.debug "poolId: $poolId | poolIdLen: $poolIdLen | newUri: $newUri | dgl_name: $uriPoolMapClass dstPool: $dstPool"
        HTTP::uri $newUri
        pool $dstPool
    } else {
         Hash out next line to disable logging
         log local0.debug "poolId: $poolId | poolIdLen: $poolIdLen | newUri: $newUri | no pool set"
         TODO this needs to be changed to reject if there isn't another iRule which ends in a deny_all
        return
    }
}
  • Okay, so basically it looks like this. Let's assume the incoming URI is /pool1/foo/bar and the virtual server is test_vs.

    when HTTP_REQUEST priority 100 {
        set poolId [string range [HTTP::uri] 1 [expr [string first "/" [HTTP::uri] 1]-1]]
         This grabs the first part of the URI ("pool1") and assigns it to a variable. So string range, starting at the second character (/ is 0), and stopping at the first occurrence of "/".
    
        set poolIdLen [string length $poolId]
         This sets the length of the above string, in this case 5.
    
        set newUri "[string range [HTTP::uri] [expr $poolIdLen+1] end]"
         This grabs everything after the first section (/foo/bar), which will become the new URI that gets passed to the application. So string range, starting at character 6 (5 + 1), going all the way to the end.
    
        set uriPoolMapClass "[string range [virtual name] 0 end-2]uri_pool_map_class"
         This creates a string based on the virtual server name (test_vs), minus the last two characters in the name (so "test_"), then appends that to the string "uri_pool_map_class", which should in this case derive the string "test_uri_pool_map_class". Presumably there's a data group named this, and inside the data group is a key-value pair, where the key is the poolId value and the value is the actual pool name.
    
        set dstPool [class lookup [string tolower $poolId] $uriPoolMapClass]
         This grabs the real pool name from the data group based on the poolId value passed in the URI.
    
        if {$dstPool ne ""} {
             Hash out next line to disable logging
             log local0.debug "poolId: $poolId | poolIdLen: $poolIdLen | newUri: $newUri | dgl_name: $uriPoolMapClass dstPool: $dstPool"
            HTTP::uri $newUri
            pool $dstPool
             Assuming there's a data group match, change the inbound URI to the server to newURI value (/foo/bar), and pool to the matched pool name.
    
        } else {
             Hash out next line to disable logging
             log local0.debug "poolId: $poolId | poolIdLen: $poolIdLen | newUri: $newUri | no pool set"
             TODO this needs to be changed to reject if there isn't another iRule which ends in a deny_all
            return
             Otherwise just use the pool that's assigned to the VIP.
    
        }
    }
    

    The whole point of this iRule is to allow an application to dictate which pool to send traffic to by injecting the pool into the URL.

  • Hi,

     

    here are some improvements of the code with comments

     

    when CLIENT_ACCEPTED {
         define the datagroup name based on virtual server.
         It is recommended to do it once per TCP connection (event CLIENT_ACCEPTED) instead of per request (event HTTP_REQUEST)
        set uriPoolMapClass "[string range [virtual name] 0 end-2]uri_pool_map_class"
    }
    
    when HTTP_REQUEST priority 100 {
         decode URI to provision both poolId and newUri variables.
        switch [scan [HTTP::uri] {/%[^/]%s} poolId newUri] {
            0 {
                Pool ID not available
                return
            }
            1 {
                 Pool ID available, but newUri not set. setting  newUri to /
                 this happens when URI is like "/poolId" and not "/poolId/path1/path2"
                set newUri "/"
            }
            2 {
                 Everything seems OK. continue.
            }
        }
        
        if {[set dstPool [class lookup [string tolower $poolId] $uriPoolMapClass]] ne ""} {
            HTTP::uri $newUri
            if {[catch {pool $dstPool}] {
                 Pool assignment fails. it may not exist and create a TCL error if not inside catch command.
                 define action here for this behavior.
                 this happens if poolId is already created in Datagroup but the pool is not created yet.
            }
        } else {
             TODO this needs to be changed to reject if there isn't another iRule which ends in a deny_all
            return
        }
    }