Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

F5 Python SDK: How to get virtual server availability?

Due to my limited Python and SDK experience I am finding it difficult to easily obtain the availability state of a virtual server. Given a 'virtual' object, what is the best/easiest way to return the value of that VS' 'Availability' state (offline, available, unknown, etc)?

I can do the following:

my_virtual = mgmt.tm.ltm.virtuals.virtual.load(name='some_virtual')
stats = my_virtual.stats.load()

Printing the stats.raw shows that there is a nested dictionary entry keyed 'status.availibityState' that appears to hold the value I'm looking for. Forgive my inexperience, but what is the easiest way to get the availability state of a virtual using the SDK? Perhaps a method I'm missing that retrieves the value above, or the value is easily obtained elsewhere.

Appreciate any assitance!

0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Great to see more people opting to use the SDK!

You can work with the output normally, as with any dict-type, using dict.get('something'). Add in a set of square-brackets, if the extracted value is yet another key-value pair, and if you're looking for a very specific match: dict.get('something')['something'].

Note: In the for-loop, I'm using virtual.name - this extraction works without use of .get('name') because 'name' is a 1st-level extraction - no nesting is involved. For the same reason, I can do state = stats.entries... in my function, instead of state = stats.get('entries')...

f5-sdk v2.2.0 ; py3.4.3 ; 11.5.4

from f5.bigip import ManagementRoot

def get_vs_state(vs_name):
    virtual_s = API_ROOT.tm.ltm.virtuals.virtual.load(name=vs_name)
    stats = virtual_s.stats.load()
    state = stats.entries.get('status.availabilityState')['description']
    return state

API_ROOT = ManagementRoot("bip-01", "admin", "admin")
VIRTUALS = API_ROOT.tm.ltm.virtuals.get_collection()

# EXAMPLE OF USE:
# Print AvailabilityState of all Virtual Servers
for virtual in VIRTUALS:
    print("Name: '%s' AvailabilityState: '%s'" % (virtual.name, get_vs_state(virtual.name)))
2
Comments on this Answer
Comment made 19-Jan-2017 by Ed Summers 1106

Thank you for your help and patience! Much appreciated...

Not sure if there is a difference in the data structures between our versions: F5 SDK v2.0.2 BIGIP 12.1.1 Python 3.3.2

When I run the stats.entries.get method you outlined above, I get a return of 'None'. However there is a value for status.availibilityState buried in nested dicts for stats.entries.

Here's a test I ran in interactive shell (I have a module that obtains a token and base object of 'mgmt'):

>>> virtuals = mgmt.tm.ltm.virtuals.virtual.load(name='my_virtual_name')
>>> stats = virtuals.stats.load()
>>> state = stats.entries.get('status.availabilityState')['description']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
>>> stats.entries
{'https://localhost/mgmt/tm/ltm/virtual/my_virtual_name/~Common~my_virtual_name/stats': {'nestedStats': {'selfLink': 'https://localhost/mgmt/tm/ltm/virtual/my_virtual_name/~Common~my_virtual_name/stats?ver=12.1.1', 'kind': 'tm:ltm:virtual:virtualstats', 'entries': {'totRequests': {'value': 0}, 'status.statusReason': {'description': 'The virtual server is available'}, 'csMinConnDur': {'value': 0}, 'fiveMinAvgUsageRatio': {'value': 0}, 'syncookie.syncookies': {'value': 0}, 'csMeanConnDur': {'value': 0}, 'tmName': {'description': '/Common/my_virtual_name'}, 'clientside.slowKilled': {'value': 0}, 'syncookie.hwSyncookies': {'value': 0}, 'ephemeral.bitsOut': {'value': 0}, 'syncookie.rejects': {'value': 0}, 'ephemeral.curConns': {'value': 0}, 'clientside.pktsOut': {'value': 0}, 'syncookie.syncacheCurr': {'value': 0}, 'clientside.bitsIn': {'value': 0}, 'ephemeral.pktsOut': {'value': 0}, 'destination': {'description': '192.168.1.1:443'}, 'syncookieStatus': {'description': 'not-activated'}, 'syncookie.hwsyncookieInstance': {'value': 0}, 'syncookie.swsyncookieInstance': {'value': 0}, 'clientside.evictedConns': {'value': 0}, 'clientside.curConns': {'value': 0}, 'clientside.totConns': {'value': 0}, 'clientside.bitsOut': {'value': 0}, 'oneMinAvgUsageRatio': {'value': 0}, 'ephemeral.totConns': {'value': 0}, 'syncookie.accepts': {'value': 0}, 'status.availabilityState': {'description': 'available'}, 'syncookie.syncacheOver': {'value': 0}, 'syncookie.hwAccepts': {'value': 0}, 'ephemeral.bitsIn': {'value': 0}, 'status.enabledState': {'description': 'enabled'}, 'ephemeral.evictedConns': {'value': 0}, 'fiveSecAvgUsageRatio': {'value': 0}, 'clientside.maxConns': {'value': 0}, 'csMaxConnDur': {'value': 0}, 'ephemeral.pktsIn': {'value': 0}, 'ephemeral.slowKilled': {'value': 0}, 'clientside.pktsIn': {'value': 0}, 'ephemeral.maxConns': {'value': 0}, 'cmpEnabled': {'description': 'enabled'}, 'cmpEnableMode': {'description': 'all-cpus'}}}}}

I'm not sure if your version is the same, but it appears the stats are nested three levels deep, first key being a link, second 'nestedStats', then 'entries'. If I follow the entire path I do get the value:

>>> print(stats.entries.get('https://localhost/mgmt/tm/ltm/virtual/my_virtual_name/~Common~my_virtual_name/stats')['nestedStats']['entries']['status.availabilityState']['description'])
    available

Am I running something incorrectly or are the returned structures different between our versions? I can run through the nest like you mentioned and get the value, though the first key (formatted as a URL) throws me off as I'm not sure if there is an elegant way to reference it. I could get it by listing the keys for that level of dict but that seems kludge-y.

0
Comment made 19-Jan-2017 by Hannes Rapp 3890

Code was tested on BigIP 11.5.4. Will update answer for 12.1.1 in 15 min.

0
Comment made 19-Jan-2017 by Hannes Rapp 3890

You're right. The response structure of virtual stats is different in 12.1.1, and it's absolutely dreadful. Best I could offer now is a hack so that this insignificant part at the beginning would be cut out {'https://localhost/mgmt/tm/ltm/virtual/my_virtual_name/~Common~my_virtual_name/stats': {'nestedStats': {, then everything will work exactly the same as in my 11.5.4 sample, but it's kind of a dirty approach.

Will look further into cleaner solutions tomorrow.

0
Comment made 19-Jan-2017 by Ed Summers 1106

Thanks! I feel better if only because it wasn't me being totally dim. :)

Everything other than the first key is static so I can look past those. The first key is dynamic...I can do an ugly hack for it. I don't like it but it will work for now.

Thanks so much for your time and testing! If you do happen across anything elegant I'm all ears!

0
Comment made 20-Jan-2017 by Hannes Rapp 3890

For Jason's reference:

entries ={'https://localhost/mgmt/tm/ltm/virtual/my_virtual_name/~Common~my_virtual_name/stats': {'nestedStats': {'selfLink': 'https://localhost/mgmt/tm/ltm/virtual/my_virtual_name/~Common~my_virtual_name/stats?ver=12.1.1', 'kind': 'tm:ltm:virtual:virtualstats', 'entries': {'totRequests': {'value': 0}, 'status.statusReason': {'description': 'The virtual server is available'}, 'csMinConnDur': {'value': 0}, 'fiveMinAvgUsageRatio': {'value': 0}, 'syncookie.syncookies': {'value': 0}, 'csMeanConnDur': {'value': 0}, 'tmName': {'description': '/Common/my_virtual_name'}, 'clientside.slowKilled': {'value': 0}, 'syncookie.hwSyncookies': {'value': 0}, 'ephemeral.bitsOut': {'value': 0}, 'syncookie.rejects': {'value': 0}, 'ephemeral.curConns': {'value': 0}, 'clientside.pktsOut': {'value': 0}, 'syncookie.syncacheCurr': {'value': 0}, 'clientside.bitsIn': {'value': 0}, 'ephemeral.pktsOut': {'value': 0}, 'destination': {'description': '192.168.1.1:443'}, 'syncookieStatus': {'description': 'not-activated'}, 'syncookie.hwsyncookieInstance': {'value': 0}, 'syncookie.swsyncookieInstance': {'value': 0}, 'clientside.evictedConns': {'value': 0}, 'clientside.curConns': {'value': 0}, 'clientside.totConns': {'value': 0}, 'clientside.bitsOut': {'value': 0}, 'oneMinAvgUsageRatio': {'value': 0}, 'ephemeral.totConns': {'value': 0}, 'syncookie.accepts': {'value': 0}, 'status.availabilityState': {'description': 'available'}, 'syncookie.syncacheOver': {'value': 0}, 'syncookie.hwAccepts': {'value': 0}, 'ephemeral.bitsIn': {'value': 0}, 'status.enabledState': {'description': 'enabled'}, 'ephemeral.evictedConns': {'value': 0}, 'fiveSecAvgUsageRatio': {'value': 0}, 'clientside.maxConns': {'value': 0}, 'csMaxConnDur': {'value': 0}, 'ephemeral.pktsIn': {'value': 0}, 'ephemeral.slowKilled': {'value': 0}, 'clientside.pktsIn': {'value': 0}, 'ephemeral.maxConns': {'value': 0}, 'cmpEnabled': {'description': 'enabled'}, 'cmpEnableMode': {'description': 'all-cpus'}}}}}

Challenge:

Please extract ['status.availabilityState']['description'] from the entries dictionary in an elegant/re-usable way. You may also instead modify the request input to come up with a less-bulky output (if there's a better way)

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

We'll need to clean up stats for sure, the nested stuff is not easy access. For all keys/values, you can get at them a little cleaner (note that if you supply partition as an argument, the self link with be /~Common~vip/~Common~vip/stats):

name = ‘testvip’
selflink = 'https://localhost/mgmt/tm/ltm/virtual/{0}/~Common~{0}/stats'.format(name)
vip = b.tm.ltm.virtuals.virtual.load(name=name)
vipstats = vip.stats.load()
d = vipstats.entries.get(selflink).get('nestedStats').get('entries')
for i in d:
  print '{0}: {1}'.format(i, d[i].get('value'))

for your specific key, given you have set the selflink above, you can get that with:

vipstats.entries.get(selflink).
                 get('nestedStats').
                 get('entries').
                 get('status.availabilityState').
                 get('description')
3
Comments on this Answer
Comment made 20-Jan-2017 by Hannes Rapp 3890

Thanks for taking your time to look into this on Friday!

So to sum it up:

  • The 1st-level dynamic key must be pre-defined with the use of placeholders to access nested keys on Stats page.
  • Supplying a partition argument to request is recommended

Overall, it would be best if the REST API response on the Stats page was a bit cleaner. As the issue is not exclusive to f5-sdk or Python users, perhaps it would make sense to consider re-working the response structure in REST API itself. Arguably, that structure was just perfect in 11.5.4.

0
Comment made 20-Jan-2017 by Jason Rahm

agreed, but will be easier to fix in SDK for short/medium term.

0
Comment made 20-Jan-2017 by Ed Summers 1106

Thank you all for your help with this! It got me through the current task and I have some ideas for another project that this will directly benefit. Hopefully I can pay it forward someday.

0
Comment made 20-Feb-2017 by Jurgen Vermeulen 0

You can find the selflink as well using a regex pattern:

for v in vs: vstats = v.stats.load() regexpat = "https://.+?"; + re.escape(v.name) + "/stats?" selflink = re.findall(regexpat,str(vstats.entries))[0]

statentries = vstats.entries.get(selflink).get('nestedStats').get('entries')
for i in statentries:
    print (i, statentries[i].get('value'))
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

This will be addressed soon, watch this issue:

https://github.com/F5Networks/f5-common-python/issues/628

1
Comments on this Answer
Comment made 20-Jan-2017 by Ed Summers 1106

Thank you!

0
Comment made 30-Jan-2017 by Ed Summers 1106

I wanted to follow-up to thank you for the amazingly fast attention to this. I checked out the development branch of the SDK and was able to pound out a quick script that takes advantage of the new stats handler. Appears to be working at least in the small test case I did testing connections and availability. Thanks kindly!

0
Comment made 04-Aug-2017 by rathid 109

@ed summers can you paste the connection and availability code for virtual here and i am looking similar things for individual members as well

0
Comment made 08-Aug-2017 by Ed Summers 1106

Replied in your other post.

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi, I am still facing issue for ver 11.6.0. I am trying to get virtual server availability status .

Appreciate any assistance .

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

I'm also struggling with this:

partition  = 'C25'
pool_name = 'temp_test'
# {u'https://localhost/mgmt/tm/ltm/pool/~C25~temp_test/~C25~temp_test/stats': {u'nestedStats': {u'entries': {u'activeMemberCnt': {u'value': 1},
pool  = mgmt.tm.ltm.pools.pool.load(name=pool_name, partition=partition)
stats = pool.stats.load()
print("{}".format(pformat(stats.entries)))

selflink = "https://{0}/mgmt/tm/ltm/pool/~{1}~{2}/~{1}~{2}/stats".format(bigip,partition,pool_name)

slink   = stats.entries.get(selflink)
nested  = slink.get('nestedStats')
entries = nested.get('entries')

activeMemberCnt = entries.get('activeMemberCnt').get('value')

Output:

Traceback (most recent call last):
  File "test_f5.py", line 46, in <module>
    nested  = slink.get('nestedStats')
AttributeError: 'NoneType' object has no attribute 'get'

So, using the example above, I am not able to get the selflink, but I have created the selflink string from what's given in the raw output. I'm working against: BIG-IP 12.1.3 Build 0.0.378 Final

0
Comments on this Answer
Comment made 25-Apr-2018 by Rob 180

Directly testing the code above:

name = 'DHCP_RELAY_255.255.255.255_VIP'
selflink = 'https://{0}/mgmt/tm/ltm/virtual/{1}/~Common~{1}/stats'.format(bigip,name)
vip = mgmt.tm.ltm.virtuals.virtual.load(name=name)
vipstats = vip.stats.load()
d = vipstats.entries.get(selflink).get('nestedStats').get('entries')
for i in d:
  print("{0}: {1}".format(i, d[i].get('value')))

I get the same error:

Traceback (most recent call last):
  File "test_f5.py", line 39, in <module>
    d = vipstats.entries.get(selflink).get('nestedStats').get('entries')
AttributeError: 'NoneType' object has no attribute 'get'
0
Comment made 25-Apr-2018 by Rob 180

See answer below...

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

This is brutal to work with!

partition  = 'C25'
pool_name = 'temp_test'
pool  = mgmt.tm.ltm.pools.pool.load(name=pool_name, partition=partition)
stats = pool.stats.load()
for item in stats.entries:
        params = stats.entries.get(item).get('nestedStats').get('entries')

stuff = ['activeMemberCnt','curSessions','serverside.curConns','serverside.maxConns','serverside.totConns','status.enabledState','status.availabilityState']

for item in stuff:
        for key in ('value','description'):
                if key in params[item]:
                        print("'{}': {}".format(item,params[item][key]))

OUTPUT:
'activeMemberCnt': 1
'curSessions': 0
'serverside.curConns': 0
'serverside.maxConns': 0
'serverside.totConns': 0
'status.enabledState': enabled
'status.availabilityState': available
0
Comments on this Answer
Comment made 30-Apr-2018 by DMA 157

Thanks a lot Rob , let me test it as well ..will update you on this..

0
Comment made 30-Apr-2018 by Jason Rahm

Have you tried the Stats module?

>>> from f5.utils.responses.handlers import Stats
>>> p = b.tm.ltm.pools.pool.load(name='testpool')
>>> ps = Stats(p.stats.load())
>>> ps.stat.curSessions['value']
0
>>> ps.stat.status_availabilityState['description']
u'offline'
>>> ps.stat.status_enabledState['description']
u'enabled'
0
Comment made 01-May-2018 by DMA 157

Hi Jason ,

I am going to test this and update the thread shortly .

0
Comment made 01-May-2018 by DMA 157

Hi Jason ,

I tested this for VIP stats and its not working ...

vis = vip.tm.ltm.virtuals.get_collection()

vi = vis.virtual.load()

ps = Stats(vi.stats.load())

error :

vi = vis.virtual.load()

AttributeError: 'list' object has no attribute 'virtual'

Can you please help me on this .. i know in earlier posts it was mentioned about F5 versions... just checking if that has been fixed ?

0