Simon- Make a copy of the f5.sap_erp template and insert the following "iapp_destination" procedure at line 3. Then replace all 5 instances of "iapp::destination" with "iapp_destination". This will allow the template to handle FQDN nodes properly on versions of BIG-IP that support FQDN nodes. You can then re-parent your deployment to the modified template.
proc iapp_destination { args } {
Set defaults. Flag actions may overwrite defaults later.
set route_domain 0
set do_mask 0
set port 0
Set up flag-based actions.
array set flags {
-route_domain { [set route_domain [iapp::pull $ptr args]] }
-mask { [set do_mask 1] }
-length { [set cidr_bits [iapp::pull $ptr args]] }
}
if { [llength [set non_switches [iapp::process_flags flags args]]] > 2 } {
error "Too many arguments"
}
if { [llength $non_switches] == 2 } { set port [lindex $non_switches 1] }
set addr [lindex $non_switches 0]
Pull the route-domain off the addr string, but only use it as the
route domain if it wasn't overridden by -route_domain flag.
if { [string first "%" $addr] != -1 } {
if { $route_domain == 0 } {
route-domain is still default, so use value from addr string
set route_domain [lindex [split $addr "%"] 1]
}
set addr [lindex [split $addr "%"] 0]
}
if { $do_mask } { ; calculate a mask
Define the delta between ipv4 and ipv6.
length: ipv4 mask is 32 bits, ipv6 is 128 bits.
group: ipv4 is grouped in octets, ipv6 as 16 bit words.
format: ipv4 is decimal notation, ipv6 is hex.
format1 also has the delimiter, format2 does not.
array set v {
0,length 32
0,group 8
0,format1 d.
0,format2 d
1,length 128
1,group 16
1,format1 .4x:
1,format2 .4x
}
Detect a node name and convert it to an ip address, then detect IPv6.
if { [string first / $addr] != -1 } {
set node [lindex [tmsh::get_config ltm node $addr] 0]
set addr [tmsh::get_field_value $node address]
}
set is_ipv6 [string match "*:*:*" $addr]
Soften result of an illegal -length parameter.
if { ![info exists cidr_bits] || $cidr_bits > $v($is_ipv6,length) } {
set cidr_bits $v($is_ipv6,length)
} elseif { $cidr_bits < 0 } {
set cidr_bits 0
}
Loop on the full length of the mask: 32 bits for ipv4, 128 for ipv6
for { set octet 0; set i 0 } { $i < $v($is_ipv6,length) } { incr i } {
Take a break at intervals to save the grouping and add delimiter.
Interval is 8 bits for ipv4 and 16 bits for ipv6.
if { $i && ![expr {$i % $v($is_ipv6,group)}] } {
Add the grouping and delimiter to the mask, then reset.
append mask [format %$v($is_ipv6,format1) $octet]
set octet 0
}
Shift the prior bits left by multiplying by 2.
Then add the current bit, which is 1 if part of the mask, 0 if not.
Current bit is part of the mask if $i < number of bits in the mask.
set octet [expr { 2 * $octet + ($i < $cidr_bits) }]
}
Add the final grouping, then return the finished mask.
set ret_val [format $mask%$v($is_ipv6,format2) $octet]
} else { ; calculate a destination
the route domain might be a name and we need a number.
if { ![string is integer $route_domain] } {
set route_domains [tmsh::get_config "/ net route-domain $route_domain"]
if { [llength $route_domains] != 1 } {
error "no such route domain: $route_domain"
}
since we have already determined that the list is 1 long,
this explicit reference to element 0 is safe
set route_domain [tmsh::get_field_value [lindex $route_domains 0] "id"]
}
set route_domain [expr { $route_domain == 0 ? "" : "%$route_domain" }]
0 and * represent wildcard port assignments in the GUI,
but TMSH requires the string 'any' to specify a wildcard.
if { $port == 0 || $port == "*" } {
set port any
}
Build the final destination. Use ":" for node names even if ipv6.
set is_ipv6_literal [string match "*:*:*" $addr]
set addr_delimiter [expr { $is_ipv6_literal ? "." : ":" }]
set ret_val ${addr}${route_domain}${addr_delimiter}${port}
}
return $ret_val
}