In version 3.0.10 of the iControl REST python SDK, we introduced a new feature that allows you to debug the API call tracing. In this article, I’ll show you how to use it to debug an issue with pool members.

Consider the following existing pool on my BIG-IP:

ltm pool testpool {
    members {
        192.168.103.20:http {
            address 192.168.103.20
            session monitor-enabled
            state up
        }
    }
    monitor http
}

You can see that there is a single pool member in this pool, 192.168.103.20:80. So when I check from the SDK to see if the pool and pool member exist, I expect the answer to be true on both counts.

>>> mgmt.tm.ltm.pools.pool.exists(name='testpool')
True
>>> pool = mgmt.tm.ltm.pools.pool.load(name='testpool')
>>> pool.members_s.members.exists(name='192.168.103.20:80')
False

Both should be true, but the pool member exists check is returning false. This is where we can engage the debug data to see what is going on with the requests.You can set the debug attribute to true when you instantiate BIG-IP, or enable it only when you need it.

>>> mgmt = ManagementRoot('ltm3.test.local', 'admin', 'admin', debug=True) # set on instantiation
>>> mgmt.debug = True  # turn on after instantiation
>>> mgmt.debug = False # turn off

Once you enable the debug attribute, the debug_output attribute will begin appending to a list the API calls made to the BIG-IP, in the format of the curl command. Note that the API is not using curl, but the debug output is formatted this way to allow you to grab the command and run it directly from the command line. For the instantiation, pool exists check, loading the pool, and then the pool member exists check, this debug output looks like this:

>>> for x in mgmt.debug_output:
... print x
...
curl -k -X GET https://ltm3.test.local:443/mgmt/tm/sys/ -H 'Connection: keep-alive' -H 'Accept-Encoding: gzip, deflate' -H 'Accept: */*' -H 'User-Agent: python-requests/2.18.4 f5-icontrol-rest-python/1.3.8' -H 'Content-Type: application/json' -H 'Authorization: Basic YWRtaW46YWRtaW4='
curl -k -X GET https://ltm3.test.local:443/mgmt/tm/ltm/pool/testpool -H 'Connection: keep-alive' -H 'Accept-Encoding: gzip, deflate' -H 'Accept: */*' -H 'User-Agent: python-requests/2.18.4 f5-icontrol-rest-python/1.3.8' -H 'Content-Type: application/json' -H 'Cookie: BIGIPAuthUsernameCookie=admin; BIGIPAuthCookie=3CF752E8B6DC27B20D42B9C2BBF152B10B400407' -H 'Authorization: Basic YWRtaW46YWRtaW4='
curl -k -X GET https://ltm3.test.local:443/mgmt/tm/ltm/pool/testpool -H 'Connection: keep-alive' -H 'Accept-Encoding: gzip, deflate' -H 'Accept: */*' -H 'User-Agent: python-requests/2.18.4 f5-icontrol-rest-python/1.3.8' -H 'Content-Type: application/json' -H 'Cookie: BIGIPAuthUsernameCookie=admin; BIGIPAuthCookie=3CF752E8B6DC27B20D42B9C2BBF152B10B400407' -H 'Authorization: Basic YWRtaW46YWRtaW4='
curl -k -X GET https://ltm3.test.local:443/mgmt/tm/ltm/pool/testpool/members/192.168.103.20:80 -H 'Connection: keep-alive' -H 'Accept-Encoding: gzip, deflate' -H 'Accept: */*' -H 'User-Agent: python-requests/2.18.4 f5-icontrol-rest-python/1.3.8' -H 'Content-Type: application/json' -H 'Cookie: BIGIPAuthUsernameCookie=admin; BIGIPAuthCookie=3CF752E8B6DC27B20D42B9C2BBF152B10B400407' -H 'Authorization: Basic YWRtaW46YWRtaW4='

After running the pool member curl command I get this response:

{"code":404,"message":"Object not found - 192.168.103.20:80","errorStack":[],"apiError":1}

Now we know why the SDK returned false, but we know this pool member exists, so what gives? If we back off and just make an API call via curl to the members collection, we can investigate the response data for clues.

{"kind":"tm:ltm:pool:members:memberscollectionstate","selfLink":"https://localhost/mgmt/tm/ltm/pool/testpool/members?ver=13.1.0.5","items":[{"kind":"tm:ltm:pool:members:membersstate","name":"192.168.103.20:80","partition":"Common","fullPath":"/Common/192.168.103.20:80","generation":175,"selfLink":"https://localhost/mgmt/tm/ltm/pool/testpool/members/~Common~192.168.103.20:80?ver=13.1.0.5","address":"192.168.103.20","connectionLimit":0,"dynamicRatio":1,"ephemeral":"false","fqdn":{"autopopulate":"disabled"},"inheritProfile":"enabled","logging":"disabled","monitor":"default","priorityGroup":0,"rateLimit":"disabled","ratio":1,"session":"monitor-enabled","state":"up"}]}

Notice in the selfLink field there, the pool member has the partition as part of the name of the pool member. If we update our curl command to include the partition (changing 192.168.103.20:80 to ~Common~192.168.103.20:80,) let's see if that fixes our 404 error:

{"kind":"tm:ltm:pool:members:membersstate","name":"192.168.103.20:80","partition":"Common","fullPath":"/Common/192.168.103.20:80","generation":175,"selfLink":"https://localhost/mgmt/tm/ltm/pool/testpool/members/~Common~192.168.103.20:80?ver=13.1.0.5","address":"192.168.103.20","connectionLimit":0,"dynamicRatio":1,"ephemeral":"false","fqdn":{"autopopulate":"disabled"},"inheritProfile":"enabled","logging":"disabled","monitor":"default","priorityGroup":0,"rateLimit":"disabled","ratio":1,"session":"monitor-enabled","state":"up"}

Woot! Now we are getting the pool member data. It turns out that the pool member call requires the partition to be submitted, even if you do not use partitions on your BIG-IP. So now, if we update our python code to include the partition parameter, it should now return true, and sure enough, that is what we get:

pool.members_s.members.exists(name='192.168.103.20:80', partition='Common')
True

The debug tracing details are documented in the SDK documentation linked at the top of this article, happy coding!