Forum Discussion

Jesse_Mauntel_4's avatar
Jesse_Mauntel_4
Icon for Nimbostratus rankNimbostratus
Nov 26, 2014

List all assigned variables

Is there a way within an iRule to list all of the assigned variables and their values without knowing the names of the variables? I'm looking for something like the 'set' or 'env' commands in bash.

 

6 Replies

  • The tcl command ">http://www.tcl.tk/man/tcl8.0/TclCmd/info.htm" target="_blank">info vars will return a list of all variables that are visible in context of that command's evaluation. This doesn't give a 'name = value' set, providing rather a Tcl list of names, but before diving into how to accomplish name/value pair listing, it might be better to understand why you are seeking to do this. Presumably it is to facilitate testing or debugging in some fashion. Are you attempting to see whether a particular variable is defined? For that, ">http://www.tcl.tk/man/tcl8.0/TclCmd/info.htm" target="_blank">info exists is a better choice.

     

    • VernonWells's avatar
      VernonWells
      Icon for Employee rankEmployee
      Sorry. The DevCentral markup system, for some reason, mangled the actual hrefs. The Tcl 'info' command is documented here: http://www.tcl.tk/man/tcl8.0/TclCmd/info.htm. The command that dumps the variable names is 'info vars'. The command to check whether a variable exists is 'info exists'.
  • 'info vars' is listing all the DG names. Can't see the variables (could be the list is too big and the log is truncated).

     

    I also tried 'info local' (as per TCL documentation) but it returned blank.

     

    Is the a documentation on info in devcentral or anywhere on the F5 website that I can refer?

     

    I'm looking for a solution to unset all local variables, and would appreciate any help in this regards please.

     

    Thanks!!

     

  • Hi Raj,

    you may try the following...

     

     

    set mytemp_var1 1
    set mytemp_var2 1
    set mytemp_var3 1
    set mytemp_var4 1
    set mytemp_var5 1
    set mytemp_var6 1
    set mytemp_var7 1
    set mytemp_var8 1
    set mytemp_var9 1
    set mytemp_var10 1
    set mytemp_var11 1
    set mytemp_var12 1
    set mytemp_var13 1
    set mytemp_var14 1
    set mytemp_var15 1
    set mytemp_var16 1
    set mytemp_var17 1
    set mytemp_var18 1
    set mytemp_var19 1
    set mytemp_var20 1
    
    log local0.debug "Classic \$mytemp_* variables: [info local mytemp_*]"
    
    set timestamp_start [clock clicks]
    
    eval "unset -nocomplain [info local mytemp_*]"
    
    set timestamp_stop [clock clicks]
    
    log local0.debug "Flushed the classic \$mytemp_* variables in [expr { $timestamp_stop - $timestamp_start - 2 }] clicks."
    log local0.debug "Leftover \$mytemp_* variables: [info local mytemp_*]"
    

     

     

    Log Output:

     

     

    Rule /Common/AA_Debug1 : Classic $mytemp_* variables: mytemp_var13 mytemp_var14 mytemp_var15 mytemp_var16 mytemp_var17 mytemp_var18 mytemp_var1 mytemp_var20 mytemp_var19 mytemp_var2 mytemp_var3 mytemp_var4 mytemp_var5 mytemp_var6 mytemp_var7 mytemp_var8 mytemp_var10 mytemp_var9 mytemp_var11 mytemp_var12
    Rule /Common/AA_Debug1 : Flushed the classic $mytemp_* variables in 31 clicks.
    Rule /Common/AA_Debug1 : Leftover $mytemp_* variables:
    

     

     

    ... or if performance is a requirement for you then change your code to use $array(variables) ...

     

     

    set mytemp(var1) 1
    set mytemp(var2) 1
    set mytemp(var3) 1
    set mytemp(var4) 1
    set mytemp(var5) 1
    set mytemp(var6) 1
    set mytemp(var7) 1
    set mytemp(var8) 1
    set mytemp(var9) 1
    set mytemp(var10) 1
    set mytemp(var11) 1
    set mytemp(var12) 1
    set mytemp(var13) 1
    set mytemp(var14) 1
    set mytemp(var15) 1
    set mytemp(var16) 1
    set mytemp(var17) 1
    set mytemp(var18) 1
    set mytemp(var19) 1
    set mytemp(var20) 1
    
    log local0.debug "Array \$mytemp variables: [array names mytemp]"
    
    set timestamp_start [clock clicks]
    
    unset -nocomplain mytemp
    
    set timestamp_stop [clock clicks]
    
    log local0.debug "Flushed the array \$mytemp variables in [expr { $timestamp_stop - $timestamp_start - 2 }] clicks."
    log local0.debug "Leftover \$mytemp variables: [array exists mytemp]"
    

     

     

    Log Output:

     

    Rule /Common/AA_Debug1 : Array $mytemp variables: var16 var7 var17 var8 var18 var9 var20 var19 var1 var10 var2 var11 var3 var12 var13 var4 var14 var5 var15 var6
    Rule /Common/AA_Debug1 : Flushed the array $mytemp variables in 3 clicks.
    Rule /Common/AA_Debug1 : Leftover $mytemp variables: 0
    

     

    Note: Using $array(variables) is much faster if you need to create AND delete them on each single request (aka. using per-request variables). Personally I always use four different kinds of $array(variables) in my own iRules. $static::global(), $session(), $conf() and $temp(). The $static::global() will store global configuration, the $session() variables will persist for an entire TCP session. The $conf() variables may changed/deleted as needed and $temp() variables will be flushed on each single request (or on demand if the containig data is large). This simple procedure makes the handling of $variables a no brainer even for the most complex iRules...

    Cheers, Kai

  • I'm curious what the intended use-case is. A variable declared outside of a namespace is scoped to the connection (in the sense of a "connection table" entry) and is destroyed when the connection closes. For something like HTTP, if one sets values in HTTP_REQUEST, the values will be overwritten for each HTTP Request message, even if they are multiplexed over a single TCP connection, because HTTP_REQUEST fires on each HTTP Request message. Ordinarily, one doesn't need to clean-up variable declarations manually.

     

    • Kai_Wilke's avatar
      Kai_Wilke
      Icon for MVP rankMVP

      Hi Vernon,

      there exist some valid usecases to perfrom variable deletions, esp. if long living keep-alive connections are beeing used. I guess the most important ones are:

      • Its frees memory at your wish (e.g. a set http_response [HTTP::payload] containig just 100kbyte for the entire connection lifetime instead of just a few CPU clicks to process the information will hurt)
      • Its required if [info exists var_name] is used as controlstatement to trigger certain codeblocks based on previous (rare) conditions or to simplify the communication between independent events.
      • Using a well designed variable handling based on request "flows" (e.g. accessing 100 objects below of a certain /uri) will not overwrite an already existing variable on each request. It would remove/assign the variables just in the case a "flow change" occours (accesing a different /uri). See the example below...

        when CLIENT_ACCEPTED {
           set session(flow) "" 
        } 
        when HTTP_REQUEST { 
           unset -nocomplain temp 
           if { [set $temp(low_path) [string tolower [HTTP::path]]] eq "/path1" } then { 
              if { $session(flow) eq "path1" } then { 
                 Keep the configuration 
              } else { 
                 set session(flow) "path1" 
                 unset -nocomplain conf 
                 set conf(param1) "xyz" 
                 set conf(param3) true 
                 set conf(param5) true 
                 set conf(param7) false 
                 set conf(param9) true 
                 set conf(param11) false 
                 set conf(param13) false 
                 set conf(param15) true 
              } 
           } else { 
              if { $session(flow) eq "else" } then { 
                 Keep the configuration 
              } else { 
                 set session(flow) "else" 
                 unset -nocomplain conf 
                 set conf(param1) "abc" 
                 set conf(param2) true 
                 set conf(param3) false 
                 set conf(param4) true 
                 set conf(param6) true 
                 set conf(param8) false 
                 set conf(param10) true 
                 set conf(param14) false 
                 set conf(param30) false 
                 set conf(param41) true 
              } 
           } 
           if { [info exists conf(param1)] } then { 
              Trigger codblock 1 
              set temp(string1) "50bytes" 
           } 
           # ...
           if { [info exists conf(param20)] } then { 
              Trigger codeblock 20 
              set temp(string20) "100bytes" 
           } 
        } 
        when HTTP_REQUEST_DATA { 
           if { [info exists conf(param21)] } then { 
              Trigger codeblock 20 
              set temp(request_payload) [HTTP::payload] 
              Code of your choice... 
              unset -nocomplain temp 
           } 
           # ... 
           if { [info exists conf(param40)] } then { 
              Trigger codeblock 40 
              set temp(string40) "50bytes" 
           } 
        } 
        when HTTP_RESPONSE { 
           if { [info exists conf(param41)] } then { 
              Trigger codeblock 41 
              set temp(string41) "100bytes" 
           } 
           # ... 
           if { [info exists conf(param60)] } then { 
              Trigger codeblock 60 
              set temp(string) "20bytes" 
           } 
        } 
        when HTTP_RESPONSE_DATA { 
           if { [info exists conf(param61)] } then {
              Trigger codeblock 61 
              set temp(request_payload) [HTTP::payload] 
              Code of your choice
              unset -nocomplain temp 
           } 
           # ... 
           if { [info exists conf(param80)] } then { 
              set temp(string) "20bytes" 
              Trigger codeblock 80 
           } 
        }

      The more complex the content-switching scenario gets and the more independent ruleset and codeblocks are required to support the individual backend ressources, the more important a good variable handling will be.

      Interesting note on using flow: I've also asked the F5 support to rollback the [pool] selection behavior in combination with [ONECONNECT] to the state of pre TMOS v12.1. Its now reverting the currently selected pool back to the default pool on each single HTTP request, so that the mentioned flow mechanic isn't able to offload the pool selections anymore (it has saved >10 CPU clicks on each single request in previous TMOS versions). ... 😞

      Cheers, Kai