IP Matching Data Profile iApp
Problem this snippet solves:
In an of itself it is not a true iApp in that it does not configure anything on the BIG-IP but it allows for configuration reuse.
Code :
cli admin-partitions { update-partition Common } cli script f5.meta_utils { proc md5sum { text } { #calcualte the md5 of text return [exec /bin/echo -n ${text} | /usr/bin/openssl dgst -md5] } proc b64en { str } { #Found at http://wiki.tcl.tk/775 binary scan ${str} B* bits switch [expr {[string length ${bits}]%6}] { 0 {set tail ""} 2 {append bits 0000; set tail ==} 4 {append bits 00; set tail =} } return [string map { 000000 A 000001 B 000010 C 000011 D 000100 E 000101 F 000110 G 000111 H 001000 I 001001 J 001010 K 001011 L 001100 M 001101 N 001110 O 001111 P 010000 Q 010001 R 010010 S 010011 T 010100 U 010101 V 010110 W 010111 X 011000 Y 011001 Z 011010 a 011011 b 011100 c 011101 d 011110 e 011111 f 100000 g 100001 h 100010 i 100011 j 100100 k 100101 l 100110 m 100111 n 101000 o 101001 p 101010 q 101011 r 101100 s 101101 t 101110 u 101111 v 110000 w 110001 x 110010 y 110011 z 110100 0 110101 1 110110 2 110111 3 111000 4 111001 5 111010 6 111011 7 111100 8 111101 9 111110 + 111111 / } ${bits}]${tail} } proc b64de { str } { #Found at http://wiki.tcl.tk/775 set tail [expr [string length ${str}] - [string length [string trimright ${str} =]]] set str [string trimright ${str} =] set bits [string map { A 000000 B 000001 C 000010 D 000011 E 000100 F 000101 G 000110 H 000111 I 001000 J 001001 K 001010 L 001011 M 001100 N 001101 O 001110 P 001111 Q 010000 R 010001 S 010010 T 010011 U 010100 V 010101 W 010110 X 010111 Y 011000 Z 011001 a 011010 b 011011 c 011100 d 011101 e 011110 f 011111 g 100000 h 100001 i 100010 j 100011 k 100100 l 100101 m 100110 n 100111 o 101000 p 101001 q 101010 r 101011 s 101100 t 101101 u 101110 v 101111 w 110000 x 110001 y 110010 z 110011 0 110100 1 110101 2 110110 3 110111 4 111000 5 111001 6 111010 7 111011 8 111100 9 111101 + 111110 / 111111 } ${str}] set bits [string range ${bits} 0 end-[expr ${tail}*2]] set bytes [binary format B* ${bits}] return ${bytes} } proc set_service_description_meta { service key value } { #create a key/value entry in a service's metadata, if it does exist update it - wrapper to set_description_meta return [set_description_meta "sys application service ${service}" ${key} ${value}] } proc delete_service_meta { service key } { #delete a services' metadata key/value based on a key - wrapper to delete_meta return [delete_meta "sys application service ${service}" ${key}] } proc get_service_description_meta { service } { #get service metadata - a wrapper for get_description_meta return [get_description_meta "sys application service ${service}"] } proc get_service_description { service } { #get service object description - just a wrapper for get_description tmsh::cd /Common return [get_description "sys application service ${service}"] } proc update_service_meta { service key value } { #update a services metadata - a wrapper for update_meta return [update_meta "sys application service ${service}" ${key} ${value}] } proc get_service_meta_value { service key } { return [get_meta_value "sys application service ${service}" ${key}] } proc get_description { object } { #return the description field, if there is nothing init the metadata info tmsh::cd /Common set desc [lindex [lindex [lindex [tmsh::get_config ${object} description] 0] [llength ${object}]] 1] if {[string match ${desc} "none"]} { tmsh::modify ${object} description \"Metadata \{[b64en "\{none foo\} [md5sum "\{none foo\}"]"]\}\" set desc "Metadata \{[b64en "\{none foo\} [md5sum "\{none foo\}"]"]\}" } return ${desc} } proc get_meta_value { object key } { set meta [get_description_meta ${object}] set index [get_meta_index ${object} ${key}] return [lindex ${meta} ${index}] } proc get_description_meta { object } { #get full metadata of the object returns a list of key/value pairs set desc [get_description ${object} ] #init results set result "none" #regexp for metadata if {[regexp {^.*Metadata\s{(.*)}$} ${desc} all r]} { set result [b64de ${r}] if {[string match [md5sum [lrange ${result} 0 end-1]] [lindex ${result} end]]} { set result [lrange ${result} 0 end-1] return ${result} } else { return "failed" } } } proc get_meta_index { object key } { #get the index of a specific key in an objects metadata, used for delete/update set meta [get_description_meta ${object}] set count 0 set found "-1" foreach item ${meta} { if {[string match [lindex ${item} 0] ${key}]} { set found ${count} } incr count } return ${found} } proc update_meta { object key value } { #update a key with a value in the metatdata for an object returns the final description set index [get_meta_index ${object} ${key}] set meta [get_description_meta ${object}] set desc_only [lrange [get_description ${object}] 0 end-2] set count 0 set buff "" foreach item ${meta} { if {[expr ${count} != ${index}]} { lappend buff ${item} } else { lappend buff "${key} ${value}" } incr count } set final "${desc_only} Metadata \{[b64en "${buff} [md5sum ${buff}]"]\}" tmsh::modify ${object} description \"${final}\" return ${final} } proc delete_meta { object key } { #delete a metadata key/value based on a key set index [get_meta_index ${object} ${key}] #desc_only excludes Metadata keyword set desc_only [lrange [get_description ${object}] 0 end-2] #init count and buff set count 0 set buff "" #look for each metadata item ... looking for the one to NOT append foreach item [get_description_meta ${object}] { if {[expr ${count} != ${index}]} { lappend buff ${item} } incr count } set final "${desc_only} Metadata \{[b64en "${buff} [md5sum ${buff}]"]\}" tmsh::modify ${object} description \"${final}\" return ${final} } proc set_description_meta { object key value} { #create a key/value entry in an objects metadata, if it does exist update it set found 0 set description [get_description ${object}] set metadata [get_description_meta ${object}] foreach s ${metadata} { if {[string match [lindex $s 0] ${key}]} { set found 1 } } #if metadata not found in metadata if { ${found} eq 0 } { #didn't find key match, there is a description, and there is metadata in that description puts "desc: ${description} [llength ${description}]" if {[expr [llength ${description}] > 2]} { #There is more than just metadata - grab none metadata set final [lrange ${description} 0 end-2] #append the key value to the end of the metadata lappend metadata "${key} ${value}" set final "${final} Metadata \{[b64en "${metadata} [md5sum ${metadata}]"]\}" } else { #there is ONLY metadata in this description lappend metadata "${key} ${value}" set final "Metadata \{[b64en "${metadata} [md5sum ${metadata}]"]\}" } tmsh::modify ${object} description \"${final}\" return ${final} } else { update_meta ${object} ${key} ${value} } } } cli script f5.ntr_utils_devcentral { proc import_service { service name } { tmsh::include "f5.meta_utils" tmsh::cd /Common set fullname ${tmsh::app_name}.app/${tmsh::app_name} set cmd "\"tmsh::modify sys application service $fullname execute-action definition\"" set_service_description_meta ${service} ${fullname} ${cmd} set objs [lindex [tmsh::get_config sys application service ${service} one-line] 0] namespace eval ${name} { proc service_var { objs pre flag } { set name [namespace current] set parent_obj $pre set count 0 foreach obj $objs { if { ([expr ${count} % 2]) and ($flag eq 0)} { variable $pre_obj $obj } elseif { ([expr ${count} % 2]) and ($flag > 0)} { variable ${parent_obj}__${pre_obj} $obj } if {([llength $obj] > 1) && ($pre_obj ne "column-names") && ($pre_obj ne "rows") } { incr flag ${name}::service_var $obj $pre_obj $flag incr flag -1 } set pre_obj $obj incr count } } proc import_tables { tables } { set name [namespace current] set table_count 0 foreach table $tables { set result "" # Only process the even elements if {![expr $table_count % 2]} { set row_count 0 foreach row [set ${name}::${table}__rows] { set column_count 0 foreach column [set ${name}::${table}__column-names] { #puts "Set ${table}(${column}__${row_count}): [lindex [lindex $row 1] $column_count]" lappend result ${column}__${row_count} lappend result [lindex [lindex $row 1] $column_count] lappend result ${column},${row_count} lappend result [lindex [lindex $row 1] $column_count] incr column_count } incr row_count } variable ${table} array set ${table} ${result} } incr table_count } } proc import_variables { vars } { set var_count 0 foreach var $vars { if {![expr $var_count % 2]} { set varname $var } else { variable ${varname} [lindex $var 1] } incr var_count } } } ${name}::service_var [lindex $objs 4] "" 0 ${name}::import_tables [set ${name}::tables] ${name}::import_variables [set ${name}::variables] } proc service_callback { } { tmsh::include "f5.meta_utils" set name $tmsh::app_name set fullname ${name}.app/${name} tmsh::cd /Common catch { foreach service [get_service_description_meta $fullname] { tmsh::cd /Common eval [lindex ${service} 1] } } } proc import_table { table_local type } { set row_count 0 array set row_result {} array set col_result {} array set rowcol_result {} foreach row ${table_local} { set element_count 0 set names "" foreach element [split $row "\n"] { if { ($element_count > 0) && ($element_count < [expr [llength [split $row "\n"]] - 1])} { if { [llength $element] > 1 } { set value "[lindex $element 1]" set column "[lindex $element 0]" lappend ary_result "${column}__${row_count}" lappend ary_result "${value}" lappend comma_result "${column},${row_count}" lappend comma_result "${value}" lappend row_result($row_count) ${value} lappend col_result($column) ${value} lappend rowcol_result($row_count) "[list $column ${value}]" lappend names $column } } incr element_count } incr row_count } switch $type { row { foreach row [array names row_result] { lappend result $row lappend result $row_result($row) } set final_result ${result} } col { foreach col [array names col_result] { lappend result $col lappend result $col_result($col) } set final_result ${result} } names { set final_result ${name}s } rowcol { foreach row [array names rowcol_result] { lappend result $row lappend result $rowcol_result($row) } set final_result ${result} } comma { set final_result $comma_result } ary { set final_result $ary_result } default { set final_result $ary_result } } return ${final_result} } proc get_items_regexp { field_name field args } { set results "" puts "args: $args" append args " recursive" set folder [tmsh::pwd] if { [catch { set objs [tmsh::get_config $args] foreach obj $objs { set name [tmsh::get_name $obj] puts "name: ${name}" puts "obj: $objs" set field_value [tmsh::get_field_value $obj $field_name] puts "field_value: $field_value" puts "field: $field" if { [regexp "$field" $field_value] } { append results "$folder/" append results [format "%s\n" ${name}] } } if { $folder != "/Common" } { tmsh::cd "/Common" append objs [tmsh::get_config $args] tmsh::cd $folder foreach obj $objs { set name [tmsh::get_name $obj] set field_value [tmsh::get_field_value $obj $field_name] if { [regexp "$field" $field_value] } { append results "/Common/" append results [format "%s\n" ${name}] } } } } err] } { puts "Command failed: tmsh::get_config $args\n $err" return ${results} } return ${results} } } sys application template /Common/f5.ip_match_profile { actions { definition { html-help { } implementation { tmsh::include "f5.ntr_utils_devcentral" if { [string match $basic__callback "Yes"]} { puts "calling back!" tmsh::run_proc f5.ntr_utils_devcentral:service_callback } } presentation { include "/Common/f5.apl_common" section basic { table ips { string network string netmask noyes invert } noyes callback #optional ( callback == "Yes" ) { # multichoice callbacks display "xlarge" tcl { tmsh::run_proc f5.ntr_utils:get_items_meta_regexp { "sys application service $tmsh::app_name.app/$tmsh::app_name" ".*app.*" } } #} } text { basic "IP Matching table" basic.ips "List of IP address" basic.ips.network "Network:" basic.ips.netmask "Netmask:" basic.ips.invert "Excetptions" basic.callback "Do you want to redeploy iApps that depend on this iApp?" } } role-acl none run-as none } } description none type failover }
Published Mar 11, 2015
Version 1.0Michael_Earnhar
Historic F5 Account
Joined October 30, 2008
Michael_Earnhar
Historic F5 Account
Joined October 30, 2008
No CommentsBe the first to comment