Generic per Object Metadata Library
Problem this snippet solves:
This library provides the methods for creating, updating, reading, and deleting per object metadata. It utilized the description field to store this data. It places the values in the form of: your description data Metadata {{ key1 value1} {key2 value2} md5_of_metadata}
note that all the metadata between the outer curly braces is base64 encoded to help keep hands off
How to use this snippet:
Example
root@sea-b-earnhart(Active)(/Common)(tmos)# list sys application service f5net.app/f5net description sys application service f5net.app/f5net { description " Metadata {e25vbmUgZm9vfSB7ZG5zX3Rlc3QuYXBwL2Ruc190ZXN0ICJ0bXNoOjptb2RpZnkgc3lzIGFwcGxpY2F0aW9uIHNlcnZpY2UgZG5zX3Rlc3QuYXBwL2Ruc190ZXN0IGV4ZWN1dGUtYWN0aW9uIGRlZmluaXRpb24ifSB7cmVuYXRhLmFwcC9yZW5hdGEgInRtc2g6Om1vZGlmeSBzeXMgYXBwbGljYXRpb24gc2VydmljZSByZW5hdGEuYXBwL3JlbmF0YSBleGVjdXRlLWFjdGlvbiBkZWZpbml0aW9uIn0gYWQyMThjMjI0NzU4ZTBkYjRmNTVmODVkMmY1MGI0NDk=}" }
if you pipe that through base64 -d you will see:
{none foo} {dns_test.app/dns_test "tmsh::modify sys application service dns_test.app/dns_test execute-action definition"} {renata.app/renata "tmsh::modify sys application service renata.app/renata execute-action definition"} ad218c224758e0db4f55f85d2f50b449
notice that it is a list of lists (the later of which are of the form {key value}), with the last element being an md5 hash of the entire list to help detect manual edits
Utility Procs
proc get_description { object } proc md5sum { text } proc b64en { str } proc b64de { str }
Wrapper Procs for iApp service objects
proc set_service_description_meta { service key value } proc delete_service_meta { service key } proc get_service_description_meta { service } proc get_service_description { service } proc update_service_meta { service key value } proc get_service_meta_value { service key }
Primary Procs
proc get_meta_value { object key } proc get_description_meta { object } proc get_meta_index { object key } proc update_meta { object key value } proc delete_meta { object key } proc set_description_meta { object key value}
Contributed by: m.earnhart
Code :
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} } } }
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