Forum Discussion

Blake_79204's avatar
Blake_79204
Icon for Nimbostratus rankNimbostratus
Feb 08, 2012

lassign alternative

I'm having a hard time finding documentation for this that is specific to Big-IP v 11, but it looks like iRules are based on Tcl 8.4.6. The command lassign wasn't introduced in Tcl until v8.5. This would explain why the command isn't listed in the disabled Tcl Commands list - it didn't exist.

 

 

Since I'm getting the following error, I figure either lassign really isn't supported, or I'm using it wrong:

 

error: line 392: [undefined procedure: lassign] [lassign $fields \ result cn goAgent goPolicyHierID goSalesID]

 

 

So, I'm hoping someone can help me devise an alternative method here:

 

 

set content [HTTP::payload]

 

 

if { $content ne "" } { log local0. "HTTP::Payload set"}

 

 

split into records in new lines

 

set records [split $content "\n"]

 

 

iterate over the records

 

foreach rec $records { split into fields on colons set fields [ split $rec ":" ]

 

 

assign fields to variables

 

lassign $fields \

 

result cn goAgent goPolicyHierID goSalesID

 

 

 

 

Any help would be appreciated.
  • just wonder if lindex which Aaron suggested in the past discussion is not applicable.

     

     

    Simple Question

     

    http://devcentral.f5.com/Community/GroupDetails/tabid/1082223/asg/39/aft/57021/showtab/groupforums/Default.aspx
  • It looks like that might work - lassign would have let me parse through each instance of $fields and set each as a variable with it's own name.

     

    I think I can use lindex to select records one at a time based upon their location in the list, but I'm not clear on how to then set that record as a new variable.

     

     

    For a little context - I'm trying to read an http page that has a list of strings (currently seperated by colons, but could be seperated by anything.) Then, once I have that list, I want to take each item and set it as an individual variable, which I'm then going to store and use elsewhere. So, really, I just need a decent way to read the list and store the values found there.
  • I'm not clear on how to then set that record as a new variable. you mean there are multiple lines in the payload and you want to keep them all, don't you? if so, may we add it into table (1 subtable per line)?

     

     

    table wiki

     

    http://devcentral.f5.com/wiki/iRules.table.ashx
  • e.g.

    [root@ve1023:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.19.79:80
       ip protocol 6
       rules myrule
       profiles {
          http {}
          tcp {}
       }
    }
    b[root@ve1023:Active] config  b rule myrule list
    rule myrule {
       when RULE_INIT {
       set static::fields {result cn goAgent goPolicyHierID goSaleID}
    }
    
    when HTTP_RESPONSE {
       set content [string trimright [HTTP::payload] "\n"]
       set records [split $content "\n"]
       table set ntable [llength $records]
    
       for {set i 0} {$i < [llength $records]} {incr i} {
          set rec [lindex $records $i]
          set fields [split $rec ":"]
    
          for {set j 0} {$j < [llength $fields]} {incr j} {
             table set -subtable line$i [lindex $static::fields $j] [lindex $fields $j]
          }
       }
    }
    
    when HTTP_RESPONSE priority 1000 {
       for {set i 0} {$i < [table lookup ntable]} {incr i} {
          for {set j 0} {$j < [llength $static::fields]} {incr j} {
             log local0. "[lindex $static::fields $j]: [table lookup -subtable line$i [lindex $static::fields $j]]"
          }
       }
    }
    }
    
    [root@ve1023:Active] config  curl http://172.28.19.79/test.html
    result1:cn1:goagent1:goplicyhierid1:gosaleid1
    result2:cn2:goagent2:goplicyhierid2:gosaleid2
    
    [root@ve1023:Active] config  cat /var/log/ltm
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : result: result1
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : cn: cn1
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : goAgent: goagent1
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : goPolicyHierID: goplicyhierid1
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : goSaleID: gosaleid1
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : result: result2
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : cn: cn2
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : goAgent: goagent2
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : goPolicyHierID: goplicyhierid2
    Feb 10 05:15:37 local/tmm info tmm[4822]: Rule myrule : goSaleID: gosaleid2
    
  • That's pretty clever - and introduces me to the trimright, table, llength, and lindex features, for which I am very grateful.

     

     

    It looks like the tables are referred to as 'session tables' --- does this mean that they are persistent with the users session?
  • It looks like the tables are referred to as 'session tables' --- does this mean that they are persistent with the users session?yes but actually, it is globally shared data among all connection and tmm.

     

     

    v10.1 - The table Command - The Basics by Spark

     

    http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/2375/v101--The-table-Command--The-Basics.aspx
  • OK - changing parameters a bit here. The initial data is all on one line, with key/value pairs seperated like this:

     

    cn=JoeAgent | Intradoc_Hrchy_Tx=somevalue | first_nm=Joe | last_nm=Agent | de3fault_agnt_id=123fake | EMAIL_ADR=agentjoe@fake.org

     

     

    The keys and variables may change without notification - so hardcoding them in as a static::field is less than ideal. The initial data is already stored as a variable (let's say it's $attributes).

     

    We can split the $attributes into records based on "|", and then split the records into fields based upon "=".

     

    Where I'm getting stumped is populating a table with those fields. How do I get it to look something like this:

     

    key | value

     

    $field1 | $field2

     

    $field3 | $field4 etc.

     

     

    I can then pull the data from the table, because I'll know the key name that I'm looking for when I need to pull it back from the table- so I can do a

     

    table lookup $field3

     

    for example, substituting the value of $field3 and getting the $field4 value returned.

     

    Any help would be appreciated.
  • Maybe this?

     

     

    set fields [split $ag_attributes "|"]

     

     

    for {set i 0} {$i < llength $fields} {incr i} {

     

    scan $fields {%[^=]=%s} $key $attribute

     

    set table -subtable attributes $key $attribute

     

     

     

    THEN LATER, TO RECALL DATA:

     

     

    table lookup -subtable attributes <$key>

     

    (input actual value of $key instead of $key)