Export Virtual Server Configuration in CSV - tmsh cli script
Problem this snippet solves: This is a simple cli script used to collect all the virtuals name, its VIP details, Pool names, members, all Profiles, Irules, persistence associated to each, in all partitions. A sample output would be like below, One can customize the code to extract other fields available too. The same logic can be allowed to pull information's from profiles stats, certificates etc. Update: 5th Oct 2020 Added Pool members capture in the code. After the Pool-Name, Pool-Members column will be found. If a pool does not have members - field not present: "members" will shown in the respective Pool-Members column. If a pool itself is not bound to the VS, then Pool-Name, Pool-Members will have none in the respective columns. Update: 21st Jan 2021 Added logic to look for multiple partitions & collect configs Update: 12th Feb 2021 Added logic to add persistence to sheet. Update: 26th May 2021 Added logic to add state & status to sheet. Update: 24th Oct 2023 Added logic to add hostname, Pool Status,Total-Connections & Current-Connections. Note: The codeshare has multiple version, use the latest version alone. The reason to keep the other versions is for end users to understand & compare, thus helping them to modify to their own requirements. Hope it helps. How to use this snippet: Login to the LTM, create your script by running the below commands and paste the code provided in snippet tmsh create cli script virtual-details So when you list it, it should look something like below, [admin@labltm:Active:Standalone] ~ # tmsh list cli script virtual-details cli script virtual-details { proc script::run {} { puts "Virtual Server,Destination,Pool-Name,Profiles,Rules" foreach { obj } [tmsh::get_config ltm virtual all-properties] { set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all"context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] puts "[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],[tmsh::get_field_value $obj "pool"],$profilelist,[tmsh::get_field_value $obj "rules"]" } } total-signing-status not-all-signed } [admin@labltm:Active:Standalone] ~ # And you can run the script like below, tmsh run cli script virtual-details > /var/tmp/virtual-details.csv And get the output from the saved file, cat /var/tmp/virtual-details.csv Old Codes: cli script virtual-details { proc script::run {} { puts "Virtual Server,Destination,Pool-Name,Profiles,Rules" foreach { obj } [tmsh::get_config ltm virtual all-properties] { set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all " context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] puts "[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],[tmsh::get_field_value $obj "pool"],$profilelist,[tmsh::get_field_value $obj "rules"]" } } total-signing-status not-all-signed } ###=================================================== ###2.0 ###UPDATED CODE BELOW ### DO NOT MIX ABOVE CODE & BELOW CODE TOGETHER ###=================================================== cli script virtual-details { proc script::run {} { puts "Virtual Server,Destination,Pool-Name,Pool-Members,Profiles,Rules" foreach { obj } [tmsh::get_config ltm virtual all-properties] { set poolname [tmsh::get_field_value $obj "pool"] set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all " context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] if { $poolname != "none" }{ set poolconfig [tmsh::get_config /ltm pool $poolname] foreach poolinfo $poolconfig { if { [catch { set member_name [tmsh::get_field_value $poolinfo "members" ]} err] } { set pool_member $err puts "[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"]" } else { set pool_member "" set member_name [tmsh::get_field_value $poolinfo "members" ] foreach member $member_name { append pool_member "[lindex $member 1] " } puts "[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"]" } } } else { puts "[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,none,$profilelist,[tmsh::get_field_value $obj "rules"]" } } } total-signing-status not-all-signed } ###=================================================== ### Version 3.0 ### UPDATED CODE BELOW FOR MULTIPLE PARTITION ### DO NOT MIX ABOVE CODE & BELOW CODE TOGETHER ###=================================================== cli script virtual-details { proc script::run {} { puts "Partition,Virtual Server,Destination,Pool-Name,Pool-Members,Profiles,Rules" foreach all_partitions [tmsh::get_config auth partition] { set partition "[lindex [split $all_partitions " "] 2]" tmsh::cd /$partition foreach { obj } [tmsh::get_config ltm virtual all-properties] { set poolname [tmsh::get_field_value $obj "pool"] set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all " context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] if { $poolname != "none" }{ set poolconfig [tmsh::get_config /ltm pool $poolname] foreach poolinfo $poolconfig { if { [catch { set member_name [tmsh::get_field_value $poolinfo "members" ]} err] } { set pool_member $err puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"]" } else { set pool_member "" set member_name [tmsh::get_field_value $poolinfo "members" ] foreach member $member_name { append pool_member "[lindex $member 1] " } puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"]" } } } else { puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,none,$profilelist,[tmsh::get_field_value $obj "rules"]" } } } } total-signing-status not-all-signed } ###=================================================== ### Version 4.0 ### UPDATED CODE BELOW FOR CAPTURING PERSISTENCE ### DO NOT MIX ABOVE CODE & BELOW CODE TOGETHER ###=================================================== cli script virtual-details { proc script::run {} { puts "Partition,Virtual Server,Destination,Pool-Name,Pool-Members,Profiles,Rules,Persist" foreach all_partitions [tmsh::get_config auth partition] { set partition "[lindex [split $all_partitions " "] 2]" tmsh::cd /$partition foreach { obj } [tmsh::get_config ltm virtual all-properties] { set poolname [tmsh::get_field_value $obj "pool"] set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all " context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] set persist [lindex [lindex [tmsh::get_field_value $obj "persist"] 0] 1] if { $poolname != "none" }{ set poolconfig [tmsh::get_config /ltm pool $poolname] foreach poolinfo $poolconfig { if { [catch { set member_name [tmsh::get_field_value $poolinfo "members" ]} err] } { set pool_member $err puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"],$persist" } else { set pool_member "" set member_name [tmsh::get_field_value $poolinfo "members" ] foreach member $member_name { append pool_member "[lindex $member 1] " } puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"],$persist" } } } else { puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,none,$profilelist,[tmsh::get_field_value $obj "rules"],$persist" } } } } total-signing-status not-all-signed } ###=================================================== ### 5.0 ### UPDATED CODE BELOW ### DO NOT MIX ABOVE CODE & BELOW CODE TOGETHER ###=================================================== cli script virtual-details { proc script::run {} { puts "Partition,Virtual Server,Destination,Pool-Name,Pool-Members,Profiles,Rules,Persist,Status,State" foreach all_partitions [tmsh::get_config auth partition] { set partition "[lindex [split $all_partitions " "] 2]" tmsh::cd /$partition foreach { obj } [tmsh::get_config ltm virtual all-properties] { foreach { status } [tmsh::get_status ltm virtual [tmsh::get_name $obj]] { set vipstatus [tmsh::get_field_value $status "status.availability-state"] set vipstate [tmsh::get_field_value $status "status.enabled-state"] } set poolname [tmsh::get_field_value $obj "pool"] set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all " context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] set persist [lindex [lindex [tmsh::get_field_value $obj "persist"] 0] 1] if { $poolname != "none" }{ set poolconfig [tmsh::get_config /ltm pool $poolname] foreach poolinfo $poolconfig { if { [catch { set member_name [tmsh::get_field_value $poolinfo "members" ]} err] } { set pool_member $err puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"],$persist,$vipstatus,$vipstate" } else { set pool_member "" set member_name [tmsh::get_field_value $poolinfo "members" ] foreach member $member_name { append pool_member "[lindex $member 1] " } puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"],$persist,$vipstatus,$vipstate" } } } else { puts "$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,none,$profilelist,[tmsh::get_field_value $obj "rules"],$persist,$vipstatus,$vipstate" } } } } total-signing-status not-all-signed } Latest Code: cli script virtual-details { proc script::run {} { set hostconf [tmsh::get_config /sys global-settings hostname] set hostname [tmsh::get_field_value [lindex $hostconf 0] hostname] puts "Hostname,Partition,Virtual Server,Destination,Pool-Name,Pool-Status,Pool-Members,Profiles,Rules,Persist,Status,State,Total-Conn,Current-Conn" foreach all_partitions [tmsh::get_config auth partition] { set partition "[lindex [split $all_partitions " "] 2]" tmsh::cd /$partition foreach { obj } [tmsh::get_config ltm virtual all-properties] { foreach { status } [tmsh::get_status ltm virtual [tmsh::get_name $obj]] { set vipstatus [tmsh::get_field_value $status "status.availability-state"] set vipstate [tmsh::get_field_value $status "status.enabled-state"] set total_conn [tmsh::get_field_value $status "clientside.tot-conns"] set curr_conn [tmsh::get_field_value $status "clientside.cur-conns"] } set poolname [tmsh::get_field_value $obj "pool"] set profiles [tmsh::get_field_value $obj "profiles"] set remprof [regsub -all {\n} [regsub -all " context" [join $profiles "\n"] "context"] " "] set profilelist [regsub -all "profiles " $remprof ""] set persist [lindex [lindex [tmsh::get_field_value $obj "persist"] 0] 1] if { $poolname != "none" }{ foreach { p_status } [tmsh::get_status ltm pool $poolname] { set pool_status [tmsh::get_field_value $p_status "status.availability-state"] } set poolconfig [tmsh::get_config /ltm pool $poolname] foreach poolinfo $poolconfig { if { [catch { set member_name [tmsh::get_field_value $poolinfo "members" ]} err] } { set pool_member $err puts "$hostname,$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_status,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"],$persist,$vipstatus,$vipstate,$total_conn,$curr_conn" } else { set pool_member "" set member_name [tmsh::get_field_value $poolinfo "members" ] foreach member $member_name { append pool_member "[lindex $member 1] " } puts "$hostname,$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,$pool_status,$pool_member,$profilelist,[tmsh::get_field_value $obj "rules"],$persist,$vipstatus,$vipstate,$total_conn,$curr_conn" } } } else { puts "$hostname,$partition,[tmsh::get_name $obj],[tmsh::get_field_value $obj "destination"],$poolname,none,none,$profilelist,[tmsh::get_field_value $obj "rules"],$persist,$vipstatus,$vipstate,$total_conn,$curr_conn" } } } } } Tested this on version: 13.08.3KViews9likes25CommentsiRule Preprocessor
Problem this snippet solves: The engine works by converting a template (which is a string, or a file) into a TCL script, and then running it. Nearly each line of text encountered will be returned as is. The exception is text between =<% ... %>= which is treated as Tcl code (the eval happens in a safe interp, see Safe Interps). This makes it very flexible and it leaves you freedom of doing what you want, dealing with any data and putting how much code you want in the template. Also for convenience there is a <%= ... %> for spooling output (the proc _defaultSpool takes care of sending the text to the right place; you can change that: see Preprocessor Commands). How to use this snippet: Template Syntax Delimiter/Command Name Description <% Code the beginning of a template code block <%= Output the beginning of a template code block that after it is evaluated by the tcl interpreter will hand the results to a function defined by printCommand option <@% Preprocessor Code the beginning of an options block used to set template options such as printCommand, logCommand <l% Default Logging Code the beginning of a logging code block with the log threshold set to 0 <l[0-9]% Level Select Logging Code the beginning of a logging code block with the log threshold set to [0-9] <l%= Default Logging Output the beginning of a logging code block with the log threshold set to 0 which after it is evaluated by the tcl interpreter will hand the results to a function defined by logCommand option <l[0-9]%= Level Select Logging Output the beginning of a logging code block with the log threshold set to [0-9] which after it is evaluated by the tcl interpreter will hand the results to a function defined by logCommand option %> Close Code/Output Block ends the current block of template code for all types of template code blocks Template Commands Command Arguments Options Returns Explanation ipp:import_irule_template BIG-IP_file_object none string templateHandle Reads the file referenced by the file object and returns a template handle ipp::setVar templateHandle templateVariable value none none set the templateVariable to "value" which will be used when ipp::render is run ipp::setLog templateHandle logLevel none none sets the global log level to a value 0-9 for the template specified by templateHandle which will be used when ipp::render is run ipp::disableLog templateHandle none none globally disables template logging statements ipp::render templateHandle none string templateResult renders out the template specified by templateHandle with all the information provided by the template and the other various methods mentioned above Simple example iRule Code when HTTP_REQUEST { set uri [HTTP::uri] if {0} { log local0. "You should never see this" } elseif {[regexp {*.jpg$} $uri]} { pool /Common/test1 } elseif {[regexp {^test*} $uri]} { pool /Common/test2 log local0. "Sending connection from: [IP::remote_addr] to pool: /Common/test1" } else { log local0. "No match Found" } } Template Code 1. when HTTP_REQUEST { 2. set uri [HTTP::uri] 3. 4. 5. 6. 7. if {0} { 8. log local0. "You should never see this" 9. <% foreach row $rows { %> 10. <% foreach {regex pool logEnabled} $row break %> 11. } elseif {[regexp {<%=$regex%>} $uri]} { 12. pool <%=$pool%> 13. <% if { $logEnabled {{}} "Yes" } { %> 14. log local0. "Sending connection from: [IP::remote_addr] to pool: <%=$pool%>" 15. <% } } %> 16. } else { 17. log local0. "No match Found" 18. } 19. } Line by Line Line Explaination Result 1 a literal line put =when HTTP_REQUEST {= into content 2 a literal line put =set uri [HTTP::uri]= into content 3 a log line with a log level threshold equal to 1 if logLevel >= 1; then put =log local0. "[HTTP::uri]"= into content 4 a log line with a log level threshold equal to 2 if logLevel >= 2; then put =log local0. "Client IP: [IP::client_addr]"= into content 5 a log line with a log level threshold equal to 4 if logLevel >= 4; then put =log local0. "Client Port: [TCP::remote_port]"= into content 6 a log line with a log level threshold equal to 3 if logLevel >= 3; then put =log local0. "Local IP: [IP::local_addr]"= into content 7 a literal line put =if {0} {= into content 8 a literal line put =log local0. "You should never see this"= into content 9 template Code evaluate =foreach row $rows {= 10 template Code evaluate =foreach {regex pool logEnabled} $row break= 11 literal with inline template Output code put =} elseif {[regexp {[puts $regex]} elseif {[regexp {= where $regex is evaluated within the template scope into content 12 literal with inline template Output code put =pool [put $pool]= where $pool is evaluated within the template scope into content 13 template Code evaluate =if { $logEnabled }} "Yes" } {= 14 literal with inline template Output code put =log local0. "Sending connection from: [IP::remote_addr] to pool: [puts $pool]"= where $pool is evaluated within the template scope into content 15 template Code evaluate =} }= 16 literal line put =} else {= into content 17 literal line put =log local0. "No match Found"= into content 18 literal line put } into content 19 literal line put } into content A few Crucial Notes the content variable is the variable where the rendered result is built up and what is eventually returned to the user as the output of {{ipp::render Preprocessor Configuration proc _newLog {args} { global content set txt "#[join $args]" append content $txt } Versions ipp.1.2.tcl.zip it works MORE perfectly (as of this writing)225Views0likes0CommentsBIG-IP Discard Server
Problem this snippet solves: This iRule oeprates in tandem with the TCP mblb profile, which is available starting in 10.x. The iRule code provides a "discard server". It accepts TCP segments, but simply discards them. It will, however, gracefully respond to a FIN. Why do this? It's useful for testing. BIG-IP can support a very large number of simultaneous connections, and a high data rate. This level of performance can be more difficult to achieve with a more conventional platform. To begin, create a virtual server with no pool members. From tmsh, execute the following: modify /ltm virtual < your_vs > profiles add { mblb } Then, add the following iRule, and apply it to your VS: Code : when CLIENT_ACCEPTED { TCP::collect } when CLIENT_DATA { TCP::payload replace 0 [TCP::payload length] "" TCP::collect }237Views0likes0CommentsCisco ACE to F5 Conversion - Python 3
Problem this snippet solves: The goal of this script is to allow for automate migration from Cisco ACE to F5 LTM configuration. It is now a little bit old and have wanted to add to it and update it for a while but other projects have kept me busy so have made it public (Code can be found here https://gitlab.com/stratalabs/ace2f5-py) This have only tested on 11.x and some 12.x configuration and not all configuration items from a Cisco ACE configuraiton convert but you normally get a warning/alert on items you will need to do manually. How to use this snippet: Generate the F5 configuration: python ace2f5.py -f <ACE configuration input file> [-o <F5 configuration output file>] [-n NOT FULLY IMPLEMENTED (will disable out, i.e. validation to screen only] If no output file is defined will output to ACE configuration file name plue '.checking' Can also run and stay in Python CLI using the -i option e.g. python -i ace2f5.py -f <ACE configuration input file> After manually checking the output file run the following to generate a clean F5 TMOS configuration file with a .output extension. This .output is the file to be imported into F5 LTM python checking-output.py -f <ace2f5.py checking file> Tested this on version: 11.6748Views2likes1CommentCisco ACE to F5 BIG-IP via tmsh
Problem this snippet solves: This script will convert Cisco ACE Configuration Files to F5 BIG-IP configuration. It is not intended to do a complete migration, but should help do the heavy lifting How to use this snippet: The script dumps to stdout, to capture in a file, use: perl ace2tmsh_v1.2.pl aceconfigfile > /var/tmp/bigip-tmsh.conf447Views0likes0CommentsCisco CSS to F5 BIG-IP via tmsh
Problem this snippet solves: This script will convert Cisco CSS Configuration Files to F5 BIG-IP configuration. It is not intended to do a complete migration, but should help do the heavy lifting. How to use this snippet: The script dumps to stdout, to capture in a file, use: perl css2f5-tmsh.pl cssconfigfile > /var/tmp/bigipconf.txt390Views0likes1CommentRadware to F5 BIG-IP via tmsh
Problem this snippet solves: This script only converts WSD text file. It does not convert ".ber" files. We may add AppDirector support at some point. Here is an explanation of the different file from one of our radware experts "Harry Kleinbourg": For some years, wsd has been replaced by AppDirector product. WSD config files could be saved in a specific format .ber. Then with an external tool, the ber file could be transform into an ascii file. Now, with AppDirector, there's only one format which is a text file. The system config-immediate isn't a config file. It's a command which shows the running config but it doesn't replace the config file. An easy way to check if you have a wsd or an appdirector is to run the command system device-info or to look into the system config-immediate : if the lines begin with "wsd" then it is a wsd, if the lines begin with appdirector then it's an appdirector. Obvious, isn't it ? How to use this snippet: The script dumps to stdout, to capture in a file, use: perl rad2f5.pl radwareconfigfile > /var/tmp/bigipconf.txt352Views0likes0CommentsCreating a tmsh script with iControl REST and using it to restart HTTPD
Problem this snippet solves: TMSH has the ability to create tcl scripts that can be used to run multiple commands and transactions. It is rare that you will want to create on with TMSH but there are a few cases where this may be desirable. One of these is to restart HTTPD, which is difficult to do from iControl REST because the REST API is running over HTTPD and the restart will not be clean. See K13292945. This Python script creates a tmsh script, and then runs it to restart HTTPD. How to use this snippet: Syntax is <program_name.py> host user password Sample output: ./rest_script_example.py10.155.117.12 admin admin Before httpd (pid 3186) is running... After httpd (pid 3289) is running... Code : #!/usr/bin/python #m.lloyd@f5.com #Makes tmsh script to restart HTTP #Syntax: host username password import json #allow python 2 and python 3 by loading the correct libraries. try: from http.client import BadStatusLine from urllib.parse import urlparse, urlencode from urllib.request import urlopen, Request from urllib.error import HTTPError except ImportError: from httplib import BadStatusLine from urlparse import urlparse from urllib import urlencode from urllib2 import urlopen, Request, HTTPError import ssl import sys import time #Internal calls will not verify certs so disable cert verification. ssl._create_default_https_context = ssl._create_unverified_context #Create request for token based authentication. This is in Bigip 12 and later: url = 'https://'+sys.argv[1]+'/mgmt/shared/authn/login' values = {'username' : sys.argv[2], 'password' : sys.argv[3], 'loginProviderName' : 'tmos'} values = json.dumps(values).encode('utf-8') Request(url,data=values) req = Request(url,data=values) req.add_header('Content-Type' , 'application/json') #Request authentication token. response = urlopen(req) #auth=result will be a json data structure. auth_result = response.read() #print (auth_result) #Json.loads makes an internal python data structure that is easier to extract auth token from json. #Now construct icontrol rest query for device-groups info. auth=json.loads(auth_result) token=(auth['token']['token']) #print(token) #Get current PID of HTTPD url = 'https://'+sys.argv[1]+'/mgmt/tm/sys/service/httpd/stats' req = Request(url) req.add_header('X-F5-Auth-Token',auth['token']['token']) response = urlopen(req,data=None) json_response=(response.read()) python_response=json.loads(json_response) print("Before") print(python_response["apiRawValues"]["apiAnonymous"]) #look for script with name to make sure that the script does not already exist url = 'https://'+sys.argv[1]+'/mgmt/tm/cli/script/example.tcl' #urllib2 raises an exception with an HTTP 404 req = Request(url) req.add_header('X-F5-Auth-Token',auth['token']['token']) try: response = urlopen(req,data=None) except HTTPError as err: if err.code==404: #print (err.code) #print("\nCreate cli script\n") #request create here url = 'https://'+sys.argv[1]+'/mgmt/tm/cli/script' req = Request(url) req.add_header('X-F5-Auth-Token',auth['token']['token']) req.add_header('Content-Type' , 'application/json') values = {"name":"example.tcl", "apiAnonymous": "proc script::init {} {\n}\n\nproc script::run {} {\n tmsh::run util bash -c 'killall -9 httpd' \n tmsh::start sys service httpd\n} \n\nproc script::help {} {\n}\n\nproc script::tabc {} {\n}\n"} values = json.dumps(values) response = urlopen(req,data=values) response_py=(json.load(response)) #print(json.dumps(response_py,sort_keys=True,indent=4)) #Now run script url = 'https://'+sys.argv[1]+'/mgmt/tm/cli/script/example.tcl' req = Request(url) req.add_header('X-F5-Auth-Token',auth['token']['token']) req.add_header('Content-Type' , 'application/json') values = {"kind":"tm:cli:script:runstate","command":"run"} values = json.dumps(values).encode('utf-8') # Killing HTTPD will abort the connection so catch the exception. try: urlopen(req,data=values) except BadStatusLine: pass #Wait for httpd to restart so you can query. time.sleep(5) #Get current PID of HTTPD after restart url = 'https://'+sys.argv[1]+'/mgmt/tm/sys/service/httpd/stats' req = Request(url) req.add_header('X-F5-Auth-Token',auth['token']['token']) response = urlopen(req,data=None) json_response=(response.read()) python_response=json.loads(json_response) print("After") print(python_response["apiRawValues"]["apiAnonymous"]) Tested this on version: 13.01.4KViews2likes2CommentsBIGIP LTM Automated Pool Monitor Flap Troubleshooting Script in Bash
Problem this snippet solves: A bash script is mainly for collecting data when F5 BIG-IP LTM pool member monitor flaps in a period of time and help determine the Root Cause of BIGIP monitor health check failure; Script will monitor the LTM logs, if new pool member down message event occurs, script will perform following functions: 1. Turn on LTM bigd debug ; 2. Start to tcpdump capture to capture relevant traffics; 3. Turn off bigd debug and terminate tcpdump process when timer elapse (timer is configurable) 4. Generate qkview (optinal) 5. Tar ball full logs files under /var/log/ directory (optinal) Script has been tested on v11.x Code : #!/usr/bin/bash ##########identify the log file that script is monitoring filename="/var/log/ltm" ##########identify the period of time that debug and tcpdump are running, please change it according to the needs; timer=60 ##########IP address of pool member flaps poolMemberIP="10.10.10.229" ##########self IP address of LTM is usd to send LTM Health Monitor traffics ltmSelfip="10.10.10.248" ##########pool member service port number poolMemberPort="443" ##########TMOS command to turn on bigd debug turnonBigdDebug="tmsh modify sys db bigd.debug value enable" ##########TMOS command to turn off bigd debug turnoffBigdDebug="tmsh modify sys db bigd.debug value disable" ##########BASH command to tar BIGIP log files tarLogs="tar -czpf /var/tmp/logfiles.tar.gz /var/log/*" ####### function file check: following code will check if /var/log/ltm exist on the system, ####### if it exists, script will be running and perform subsequent functions if [ -f $filename ] then echo "/var/log/ltm exists and program is running to collect data when BG-IP pool member flaps" else ####### if it does not exist, programe will be terminated and log following message echo "no /var/log/ltm file found and program is terminated" exit 0 fi ####### function file check ends ###### write timestap to /var/log/ltm for tracking purpose echo "$(date) monitoring the log" >> $filename ###### start to monitor the /var/log/ltm for new events tail -f -n 0 $filename | while read -r line do ###### counter for pool down message appears hit=$(echo "$line" | grep -c "$poolMemberIP:$poolMemberPort monitor status down") #echo $hit ###### if [ "$hit" == "1" ]; then ###### diplay the pool down log event in file /var/log/ltm echo $line ###### show timestamp of debug is on echo "$(date) Turning on system bigddebug" ###### turn on bigd debug echo $($turnonBigdDebug) ###### turn on tcpdump capture echo $(tcpdump -ni 0.0:nnn -s0 -w /var/tmp/Monitor.pcap port $poolMemberPort and \(host $poolMemberIP and host $ltmSelfip\)) & ###### running timer sleep $timer ###### show timestamp of debug is off echo "$(date) Truning off system bigddebug" ###### turn off bigd debug echo $($turnoffBigdDebug) ###### terminate tcpdump process echo $(killall tcpdump) ###### generate qkview, it's an optional function, enable it by remove "#" sign #echo $(qkview) ###### tar log files, it's an optional function, enable it by remove "#" sign #echo $($tarLogs) break #else #echo "Monitor in progress" fi done ###### show message that programe is end echo "$(date) exiting from programe" ###### exit from the program exit 0 Tested this on version: 11.6942Views0likes6CommentsExport GTM/DNS Configuration in CSV - tmsh cli script
Problem this snippet solves: This is a simple cli script used to collect all the WideIP, LB Method, Status, State, Pool Name, Pool LB, Pool Members, Pool Fall back, Last Resort pool info in CSV format. A sample output would be like below, One can customize the code to extract other fields available too. Check out my other codeshare of LTM report. Note: The codeshare may get multiple version, use the latest version alone. The reason to keep the other versions is for end users to understand & compare, thus helping them to modify to their own requirements. Hope it helps. How to use this snippet: Login to the GTM/DNS, create your script by running the below commands and paste the code provided in snippet, tmsh create cli script gtm-config-parser Delete the proc blocks, so it looks something like below, create script gtm-config-parser { ## PASTE THE CODE HERE ## } and paste the code provided in the snippet. Note: When you paste it, the indentation may be realigned, it shouldn't cause any errors, but the list output would show improperly aligned. Feel free to delete the tab spaces in the code snippet & paste it while creating, so indentation is aligned properly. And you can run the script like below, tmsh run cli script gtm-config-parser > /var/tmp/gtm-config-parser-output.csv And get the output from the saved file, open it on excel. Format it & use it for audit & reporting. cat /var/tmp/gtm-config-parser-output.csv Feel free to add more elements as per your requirements. For version 13.x & higher, there requires a small change in the code. Refer the comments section. Thanks to @azblaster Code : proc script::run {} { puts "WIP,LB-MODE,WIP-STATUS,WIP-STATE,POOL-NAME,POOL-LB,POOL-MEMBERS,POOL-FB,LASTRESORT-POOL" foreach { obj } [tmsh::get_config gtm wideip all-properties] { set wipname [tmsh::get_name $obj] set wippools [tmsh::get_field_value $obj pools] set lbmode [tmsh::get_field_value $obj "pool-lb-mode"] set lastresort [tmsh::get_field_value $obj "last-resort-pool"] foreach { status } [tmsh::get_status gtm wideip $wipname] { set wipstatus [tmsh::get_field_value $status "status.availability-state"] set wipstate [tmsh::get_field_value $status "status.enabled-state"] } foreach wippool $wippools { set pool_name [tmsh::get_name $wippool] set pool_configs [tmsh::get_config /gtm pool $pool_name all-properties] foreach pool_config $pool_configs { set pool_lb [tmsh::get_field_value $pool_config "load-balancing-mode"] set pool_fb [tmsh::get_field_value $pool_config "fallback-mode"] if { [catch { set member_name [tmsh::get_field_value $pool_config "members" ]} err] } { set pool_member $err } else { set pool_member "" set member_name [tmsh::get_field_value $pool_config "members"] foreach member $member_name { append pool_member "[lindex $member 1] " } } puts "$wipname,$lbmode,$wipstatus,$wipstate,$pool_name,$pool_lb,$pool_member,$pool_fb,$lastresort" } } } } Tested this on version: 11.63.6KViews2likes6Comments