iApp Implementation v11.4

Decision-making arrays and the iapp:: namespace package are two v11.4 enhancements described in this brief.

iApp Tcl on BIG-IP v11.4

A number of changes and enhancements were made to the suite of F5-supported iApps in the v11.4 release. All v11.4 templates share common code from the v11.4 iapp:: namespace, and obtain that code from Tcl packages rather than cli scripts. In addition, all v11.4 templates and ESD templates released after December 2012 use new coding practices, such as array-based decision trees. This article describes these changes and how they affect iApp users.

Decision-Making with Tcl Arrays

Much of what an iApp does is translation. It obtains a set of presentation data, forms it into command language instructions, and delivers the instructions to the operating system. The hallmark of a well-written iApp, therefore, is its ability to derive a correct and useful TMOS configuration from a minimum set of easily-understood user inputs. Due to this common purpose, iApps typically share the need for the decision-making aspects of the programming language more than, say, floating-point operations. The obvious mechanism for decision-making in Tcl, as with most languages, is the “if-then” statement. These statements are easily understood when isolated, but become confusing when deeply nested or embracing long, complex expressions. An alternative in these situations is to use arrays. The concept is two-fold. First, reduce your decision into a few equations that have binary or otherwise very limited outcomes, storing the results as key variables. Second, build an array of executable statements paired with key value combinations. The following example illustrates the basic idea.
“if-then” decision
if { $feel == “drowsy” } {
    if { $taste == “sweet” } {
        puts “Coffee with sugar, please”
    } else {
        puts “Coffee black, please”
    }
} else {
        puts “Just water, thanks”
    }
}

array-based decision
# array keys: $feel,$taste
array set coffee {
    drowsy,sweet  {[puts “Coffee with sugar, please” ]}
    drowsy,bitter {[puts “Coffee black, please” ]}
    alert,sweet   {[puts “Just water, thanks” ]}
    alert,bitter  {[puts “Just water, thanks” ]}
}
subst $coffee($feel,$taste)

This example shows how an array obviates the decision paths, but this is both a strength and a weakness. The weakness is that all possible keys must be declared, or you risk execution failure. The PME group partially solved this problem by writing a “subst” statement wrapper that allows a default outcome. This proc, called “substa,” is included in the v11.4 release. The following example illustrates how its use differs from the native Tcl “subst,” simplifying the array and preventing potential key non-existence errors.
# array keys: $feel,$taste
array set coffee {
    drowsy,sweet  {[puts “Coffee with sugar, please” ]}
    drowsy,bitter {[puts “Coffee black, please” ]}
*             {[puts “Just water, thanks” ]}
}
iapp::substa coffee($feel,$taste)

Below is a typical use of array-based decision-making for virtual server configuration. It uses pre-calculated binary keys to choose the correct port, and create a second virtual for redirect if required.
# VIRTUAL SERVERS
set do_client_ssl [expr { [iapp::is ::ssl__offload yes] }]
set do_redirect   [expr { [iapp::is ::pool__redirect_to_https yes] }]

# array keys: $do_client_ssl,$do_redirect
array set vs_arr {
    1,1 { [iapp::conf create ltm virtual my_vs \
          destination ${::pool__addr}:443 \
          pool mypool \
          profiles replace-all-with \{ http \}] \
          [iapp::conf create ltm virtual my_redir_vs \
          destination ${::pool__addr}:80 \
          pool none \
          profiles replace-all-with \{ http \}] }
    1,0 { [iapp::conf create ltm virtual my_vs \
          destination ${::pool__addr}:443 \
          pool mypool \
          profiles replace-all-with \{ http \}] }
    *   { [iapp::conf create ltm virtual my_vs \
          destination ${::pool__addr}:80 \
          pool mypool \
          profiles replace-all-with \{ http \}] }
}

iapp::substa vs_arr($do_client_ssl,$do_redirect)

Note that Tcl does not explicitly support multidimensional arrays, but any string may be used as a key. In the example above, the key “1,1” is a 3-character key in a one-dimensional array, not a numeric key in a 2-dimensional array. Inserting whitespace (“1, 1”) will break the assignment statement. Further discussion of Tcl arrays may be found at http://wiki.tcl.tk/1032. It is also important to understand that these decision-making arrays may be, and often are, nested. The following example shows an array that generates an ltm pool (itself a product of arrays) being used in the virtual server array from the prior example.
# POOL
set new_pool [iapp::is ::pool__pool_to_use $CREATE_NEW_ANSWER]

# array keys: $new_pool,$do_server_ssl
array set pool_arr {
    1,1 { pool [iapp::conf create ltm pool my_pool \
        [iapp::substa pool_ramp_pga_arr($advanced,$do_slow_ramp,$do_pga)] \
        [iapp::substa pool_lb_queue_arr($advanced,$tcp_queuing)] \
        [iapp::substa monitor_arr($do_monitor,$new_monitor,$advanced)] \
        [iapp::pool_members $::pool__members]] }
    1,0 { pool [iapp::conf create ltm pool my_pool \
        [iapp::substa pool_ramp_pga_arr($advanced,$do_slow_ramp,$do_pga)] \
        [iapp::substa pool_lb_queue_arr($advanced,$tcp_queuing)] \
        [iapp::substa monitor_arr($do_monitor,$new_monitor,$advanced)] \
        [iapp::pool_members $::pool__members]] }
    0,1 { pool $::pool__pool_to_use }
    0,0 { pool $::pool__pool_to_use }
}

# VIRTUAL SERVERS
set do_client_ssl [expr { [iapp::is ::ssl__offload yes] }]
set do_redirect   [expr { [iapp::is ::pool__redirect_to_https yes] }]

# array keys: $do_client_ssl,$do_redirect
array set vs_arr {
    1,1 { [iapp::conf create ltm virtual my_vs \
          destination ${::pool__addr}:443 \
          pool [iapp::substa $pool_arr($new_pool,$do_server_ssl)] \
          profiles replace-all-with \{ http \}] \
          [iapp::conf create ltm virtual my_redir_vs \
          destination ${::pool__addr}:80 \
          pool none \
          profiles replace-all-with \{ http \}] }
    1,0 { [iapp::conf create ltm virtual my_vs \
          destination ${::pool__addr}:443 \
          pool [iapp::substa $pool_arr($new_pool,$do_server_ssl)] \
          profiles replace-all-with \{ http \}] }
    *   { [iapp::conf create ltm virtual my_vs \
          destination ${::pool__addr}:80 \
          pool [iapp::substa $pool_arr($new_pool,$do_server_ssl)] \
          profiles replace-all-with \{ http \}] }
}

iapp::substa vs_arr($do_client_ssl,$do_redirect)

The iapp_11_4_0 Tcl Package and iapp:: Namespace

In prior releases, common code has been stored in an F5-supported cli script called “app_utils.” In v11.4, app_utils is still supported, but F5-supported templates have been migrated to the “iapp_11_4_0” package and logically protected within the “iapp::” namespace. Tcl packages support versioning and occupy a smaller memory footprint than cli scripts. Namespaces help to prevent conflicts between template code and common code. There are syntactic differences between these methods, but the end goal is achieved in both cases, i.e. multiple templates are able to share common procedures. example use of cli script in v11.3 tmsh::include “f5.app_utils” set provisioned tmsh::run_proc f5.app_utils:get_provisioned wam
example use of Tcl package in v11.4
package require iapp 1.0.0
set provisioned [iapp::get_provisioned wam -is]

In addition to the new location, the common code itself has undergone a significant revision. Many of the v11.3 app_util functions have been consolidated into a few generic procedures, while new procedures such as “is” and “substa” have been included to support the v11.4 array-based programming style.

The BIG-IP API Reference documentation contains community-contributed content. F5 does not monitor or control community code contributions. We make no guarantees or warranties regarding the available code, and it may contain errors, defects, bugs, inaccuracies, or security vulnerabilities. Your access to and use of any code available in the BIG-IP API reference guides is solely at your own risk.