Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

iApp variable scope

Hi all,

I'm writing my first iApp to automate deployment of a few virtual servers, nodes, pools and iRule data-groups

I have finished the presentation section and am now starting on the implementation. One issue that I'm having though is referencing variables assigned from the presentation within tmsh::create, tmsh:modify etc

I can read the variables back fine within the base iApp, for example I have the following:

puts "Adding SNAT data. $::private__privateAddr maps to $::public__publicAddr"

Which logs the following in scriptd.out:

Adding SNAT data. xxx.xxx.xxx.xxx maps to xxx.xxx.xxx.xxx

Where I run into the issue though is referencing the same variables in tmsh::modify.

For example I have the following:

proc tmsh_modify { args } {
    set args [join $args]
    puts "tmsh modify $args"
    tmsh::modify $args
    return [lindex $args [lsearch -glob $args "*_*"]]
}

puts "Adding SNAT data.  $::private__privateAddr maps to $::public__publicAddr"

tmsh_modify { ltm data-group internal /Common/snat-map
  records add { 
    $::private__privateAddr { 
      data $::public__publicAddr
    } 
  }
}

This logs the following:

[root@ltm02-dev:Active:Changes Pending] config # tail -f /var/tmp/scriptd.out -n0
    Adding SNAT data.  xxx.xxx.xxx.xxx maps to xxx.xxx.xxx.xxx
    tmsh modify  ltm data-group internal /Common/snat-map
      records add { 
        $::private__privateAddr { 
          data $::public__publicAddr
        } 
      }

So from this I can see the variables are being treated as normal strings. As expected this errors out on the iApp creation screen:

script did not successfully complete: ("$::private__privateAddr" invalid address
    while executing
    "tmsh::modify $args"
    (procedure "tmsh_modify" line 4)
    invoked from within
    "tmsh_modify { ltm data-group internal /Common/snat-map
    records add { 
    $::private__privateAddr { 
    data $::public__publicAddr
    } ..." line:14)

I couldn't find any specific information on the scope of variables when used in this manner, perhaps it is just a simple issue of syntax.

I'd appreciate if someone can give me some guidance on this.

Thanks!

0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Scope is not the problem. Tcl treats anything inside curly braces as verbatim. Enclosed strings in quotes and escape each curly brace with a backslash.

tmsh_modify "ltm data-group internal /Common/snat-map records add { $::private__privateAddr { data $::public__publicAddr }}"

0
Comments on this Answer
Comment made 21-May-2015 by Fred Slater
This wiki is not displaying what I am typing. You must add a backslash before each curly brace above.
0
Comment made 21-May-2015 by Uber Nathan 1
Thanks a lot Fred, all working now :)
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi Fred! I've a similar questions:

I'm modifying an iApp in order to create an irule to assign to the vs.

the assignment is here { [iapp_conf create ltm virtual ${app}_vs \ destination [iapp_destination $::pool__addr $::pool__port] \ mask $mask \ $vs_params \ ip-protocol tcp \ mirror $mirror_action \ profiles replace-all-with { $tcp_profiles http } \ rules { iwf_test_irulebal iwf_$irulelog }] }

the irule are very simple

the first irule is with no variables

tmsh::create ltm rule iwf_$irulelog {

when HTTP_REQUEST { 
    log local0. "No variables" 
}
`</pre>

}

the second irule need to balance on the pool created with the iapp, so i need to write it with variable statement and not with string

<pre>`iapp_conf create ltm rule iwf_test_irulebal {

when HTTP_REQUEST { 

if { [HTTP::uri] starts_with "/portal${app}_pool" } {
    use pool ${app}_pool }
else {
    TCP::close
}
}
}

i've tried with \before the { but seems not works. also with ::global variable but not works.

In a classic BIG-IP environment without iapp the use of variable in irule works. how can i use the variable in an irule created with an iapp?

0
Comments on this Answer
Comment made 30-Oct-2017 by Fred Slater

I typically use string map.

set app "xyz"

set irule [string map "<APP> $app" {
when HTTP_REQUEST {
  if { [HTTP::uri] starts_with "/portal<APP>_pool" } {
    use pool <APP>_pool }
  else {
    TCP::close
  }
}
}]

iapp::conf create ltm rule iwf_test_irulebal $irule
0
Comment made 06-Nov-2017 by jojo83 69

Hi Fred,

I tried your suggestion but I encountered some problem with the variable "Iwf_test_irulebal".

in the meantime I had solved this

set :: iapp_sn $ tmsh :: app_name set :: pool_irule $ {:: iapp_sn} _pool

set infile1 [open "/var/tmp/irule.tmp" "w" "0644"] puts $ infile1 "ltm rule /Common/$::iapp_sn.app/irule$::iapp_sn \ {" puts $ infile1 "app-service $ :: iapp_sn" puts $ infile1 "when HTTP_REQUEST \ {" puts $ infile1 "if \ {\ [HTTP :: uri ] starts_with \" / portal $ :: iapp_sn \ "} \ {" puts $ infile1 "use pool $ :: pool_irule }" puts $ infile1 "elseif \ {\ [HTTP :: uri ] starts_with \" / script $ :: iapp_sn \ "} \ {" puts $ infile1 "use pool $ :: pool_irule }" puts $ infile1 "else \ {" puts $ infile1 "TCP :: close" puts $ infile1 "}" puts $ infile1 "}" puts $ infile1 "}" close $ infile1

tmsh :: load sys config merge check file /var/tmp/irule.tmp

file delete "/var/tmp/irule.tmp"

set irulevs "/Common/$::iapp_sn.app/irule$::iapp_sn"

and it works.

but in the end I did as suggested by crodriguez.

https://devcentral.f5.com/questions/create-irule-with-variable-in-iapp-56337

thanks anyway Regards

0