Forum Discussion

Ed_Summers's avatar
Ed_Summers
Icon for Nimbostratus rankNimbostratus
Jan 19, 2017

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!

27 Replies

  • 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)))
    
    • Ed_Summers's avatar
      Ed_Summers
      Icon for Nimbostratus rankNimbostratus

      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 "", line 1, in 
      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.

    • Hannes_Rapp's avatar
      Hannes_Rapp
      Icon for Nimbostratus rankNimbostratus

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

       

    • Hannes_Rapp's avatar
      Hannes_Rapp
      Icon for Nimbostratus rankNimbostratus

      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.

  • 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)))
    
    • Ed_Summers's avatar
      Ed_Summers
      Icon for Nimbostratus rankNimbostratus

      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 "", line 1, in 
      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.

    • Hannes_Rapp_162's avatar
      Hannes_Rapp_162
      Icon for Nacreous rankNacreous

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

       

    • Hannes_Rapp_162's avatar
      Hannes_Rapp_162
      Icon for Nacreous rankNacreous

      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.

  • 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')
    
    • Ed_Summers's avatar
      Ed_Summers
      Icon for Nimbostratus rankNimbostratus

      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!

       

    • rathid's avatar
      rathid
      Icon for Nimbostratus rankNimbostratus

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

       

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

     

    Appreciate any assistance .

     

  • 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 
        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

    • Rob_74473's avatar
      Rob_74473
      Icon for Cirrus rankCirrus

      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 
          d = vipstats.entries.get(selflink).get('nestedStats').get('entries')
      AttributeError: 'NoneType' object has no attribute 'get'
  • 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
    
    • DMA_95966's avatar
      DMA_95966
      Icon for Nimbostratus rankNimbostratus

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

       

    • JRahm's avatar
      JRahm
      Icon for Admin rankAdmin

      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'
      
    • DMA_95966's avatar
      DMA_95966
      Icon for Nimbostratus rankNimbostratus

      Hi Jason ,

       

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