Pool member status on F5 DNS objects via iControl REST
I got a question on how to retrieve the status of pool members on F5 DNS objects via the iControl REST interface. In the GUI you get fancy red, yellow, black, blue, and green painted circles, diamonds, squares, and triangles to communicate availability. At the command line, however, it’s harder to map that visual data. There are two important settings underlying an object’s availability: availability state and enabled state. You can see when using the field-fmt option on the tmsh command to show the pool member status that both GTM and LTM objects report the same data (the remaining fields are removed for brevity):
gtm pool pool gslb_pool_1:A { members { testvip:ltm3 { status.availability-state available status.enabled-state enabled status.status-reason Available } } status.availability-state available status.enabled-state enabled status.status-reason Available } ltm pool testpool { members { 192.168.103.20:80 { status.availability-state available status.enabled-state enabled status.status-reason Pool member is available } } status.availability-state available status.enabled-state enabled status.status-reason The pool is available }
Through the REST interface, both status fields are available in the LTM pool object. Calling the pool member and selecting on session and state, the following request returns the data as expected:
GET https://ltm3.test.local/mgmt/tm/ltm/pool/testpool/members/~Common~192.168.103.20:80?$select=session,state { "session": "monitor-enabled", "state": "up" }
However, these same status fields are not available on GTM pool/pool member REST objects. Calling a GTM pool member, the following request returns no information on monitor status (that's the availability-state field from above) but does indicate the enabled state, albeit unconventionally by changing the field name:
GET https://ltm3.test.local/mgmt/tm/gtm/pool/a/~Common~gslb_pool_1/members/~Common~ltm3:~Common~front_door # when enabled: { "name": "front_door", "enabled": true, } # when disabled: { "name": "front_door", "disabled": true, }
So if the information is not available directly from the REST interface, how do you get it? Well, you have options. The newest approach (and one I am currently investigating for things like this) is writing your own API via the iControl LX extensions. That's not the approach I'll take here, however. Instead, I'll use a tmsh script to return the appropriate data via a bash call from iControl REST.
The tmsh script is quite simple. It takes an argument for the type of GTM pool you wish to query, and then the pool name. It will then iterate through the members and return for each member the pool member name, its availability state, and its enabled state.
proc script::run {} { if { $tmsh::argc != 3 } { puts "A pool type and name must be provided" exit } set pool_type [lindex $tmsh::argv 1] set pool_name [lindex $tmsh::argv 2] foreach obj [tmsh::get_status /gtm pool $pool_type $pool_name detail] { foreach member [tmsh::get_field_value $obj members] { puts "[tmsh::get_name $member],[tmsh::get_field_value $member status.availability-state],[tmsh::get_field_value $member status.enabled-state]" } } } total-signing-status not-all-signed }
Running the script from bash on the BIG-IP, I get the following results:
[root@ltm3:Active:Standalone] tmp # tmsh run cli script pool-status.tcl a gslb_pool_1 front_door:ltm3,available,disabled testvip:ltm3,available,enabled testvip2:ltm3,available,enabled
And finally, calling this with the F5 python SDK returns the same results:
>>> from f5.bigip import ManagementRoot >>> mgmt = ManagementRoot('ltm3.test.local', 'admin', 'admin', token=True) >>> ps = mgmt.tm.util.bash.exec_cmd('run', utilCmdArgs='-c "tmsh run cli script pool-status.tcl a gslb_pool_1"') >>> ps.commandResult u'front_door:ltm3,available,disabled\ntestvip:ltm3,available,enabled\ntestvip2:ltm3,available,enabled\n'
You can of course modify the tmsh script to return the data in a different format, I opted for quick and dirty here to model the problem and solution. Thanks go to community member Aaron Murray for the question and the inspiration, happy coding out there!
- IRONMANCirrostratus
Thanks, Now i can add this feature to my API Kit, to do some features in tmsh & Bash apart from Rest calls.
- John_AllenAltostratus
Is there a way to SET the state of a BIG-IP DNS Pool? In my downstream LTMs, I can intercept error conditions for nodes using an iRule, and if the local Pool has no other members up, I want to signal the BIG-IP DNS that the service is down right away, so I can respond to the client to re-query DNS and pick up another data center. The problem I have is that if I have to wait for all the Health Checks to timeout (both locally on the LTM, and then up on the DNS), the BIG-IP DNS could re-pick the data center with the down service in the meantime, and cause my request to loop.
- JRahmAdmin
Hi John, you can use bash to run tmsh commands, so state is indeed possible by using tmsh modify on the pool member:
tmsh show gtm pool a gslb_pool_1 members | grep State State : enabled | State : enabled tmsh modify gtm pool a gslb_pool_1 members modify { ltm3:/Common/testvip { disabled }} tmsh show gtm pool a gslb_pool_1 members | grep State State : enabled | State : disabled
- Vincent_95972Nimbostratus
I can't seem to get that JSON data from your instructions above.
I get the expected results from running the script from bash on the BIG-IP:
[me@BIGIPDNS1:Active:Standalone] ~ tmsh run cli script BIGIPDNSpoolmemberstatus.tcl a MY_POOL VIRTUAL_SERVER_1_443:LTMSFRML1ab,available,enabled VIRTUAL_SERVER_2_443:LTMSFRML1ab,available,enabled
However, calling it from a Python file that I created didn't give me the JSON results like what you were able to demonstrate above. Below is my code in my Python file:
…
mgmt = ManagementRoot( mydevice, myuser, mypassword) ps = mgmt.tm.util.bash.exec_cmd('run', utilCmdArgs='-c "tmsh run cli script BIGIPDNSpoolmemberstatus.tcl a MY_POOL"')
ps.commandResult
No errors are shown when executing the above but I am unable to print the JSON data. For example, it would result in an error if I do a "print ps.commandResult". The errors I always get say that "The requested shell script (/Common/BIGIPDNSpoolmemberstatus.tcl) was not found". Again, I am able to run this TMSH script from the BIG-IP in success.
Not sure what I am missing or doing wrong.
- JRahmAdmin
are partitions enabled on your device? Try updating your call from REST with the partition on the object.
- Vincent_95972Nimbostratus
Thank you for your prompt response. Here's an update for you. I was able to successfully post it and get the results (i.e.\commandResult) in Postman using the following:
POST:
Body: { "command":"run", "utilCmdArgs":"-c 'tmsh run cli script BIGIPDNSpoolmemberstatus.tcl a MY_POOL'" }
So... I'm now just trying to translate that into my Python code. I'm quite new to the F5 SDK as I just started working on it this week so I'm not sure how to get that written into my Python code. What you provided above makes sense but I'm not sure what else is missing or in question in my Python code?
I think it's safe to rule out partitions given that I'm now able to get the expected results from a different means (being Postman).
- JRahmAdmin
running same user permissions from postman, tmsh, and python? if it's not seeing the script, that seems like either a partition or permission problem, but I'm not sure where the issue is based on your feedback.
- Vincent_95972Nimbostratus
I see. I did use my user account when following the instructions you provided for creating the tcl file above and testing the results. Running the APIs in all cases were done using the admin account. Looking into it now to see if that may be the underlying issue.
- JRahmAdmin
If you have a remote authentication configured on BIG-IP, you could try adding token=True as a kwarg to your ManagementRoot call to see if that fixes things.
- Vincent_95972Nimbostratus
Created the TCL file and tested it in BASH using the admin account. I'm still unable to get that JSON data when running my Python code. I'm getting 400 code errors now. Will look into adding token=True.