For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Brian_Menges_10's avatar
Brian_Menges_10
Icon for Nimbostratus rankNimbostratus
Nov 19, 2012

iControl + Python + add_member / remove_member

So I'm trying to get a handle on add and remove _member functions using pycontrol (v2).

I can't seem to get add/remove working correctly. Can someone help me out?

Here's what I attempted to hack from a base script

Base: https://devcentral.f5.com/wiki/iCon...ember.ashx

Code attempted:

import sys

import pycontrol.pycontrol as pc

import time

if len(sys.argv) < 7:

print "Usage %s ip_address username password" % sys.argv[0]

print "Usage %s ip_address username password pool_name member action" % sys.argv[0]

sys.exit(1)

a = sys.argv[1:]

POOL = sys.argv[4]

members = [sys.argv[5]]

action = sys.argv[6]

The constructor is similar to the original pyControl.

Note the change from wsdl_files to wsdls, which makes more sense.

b = pc.BIGIP(

hostname = a[0],

username = a[1],

password = a[2],

fromurl = True,

wsdls = ['LocalLB.PoolMember','LocalLB.Pool'])

--------- helper methods below ----------

def member_factory(b, member):

'''

Produces a Common.IPPortDefinition object per member ip:port combination

object per member ip:port combination. Add these to Common.IPPortDefinitionSequence.

args: a pycontrol LocalLB.PoolMember object and an ip:port

combination that you'd like to add.

'''

ip,port = member.split(':')

pmem = b.LocalLB.PoolMember.typefactory.create('Common.IPPortDefinition')

pmem.address = ip

pmem.port = int(port)

return pmem

def session_state_factory(b, members):

'''

Returns session state objects. Returns a list of session state objects with associated

members.

'''

session_states = []

create a type of: 'LocalLB.PoolMember.MemberSessionState'

Inside of this type, you'll see that it expects a pool member as an

attribute. Let's create that, set our attributes (address, port), and add it to sstate

above.

for x in members:

sstate = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionState')

sstate.member = member_factory(b,x)

sstate.session_state = 'STATE_DISABLED'

session_states.append(sstate)

return session_states

The session state sequence object. Takes a list of 'member session state'

objects.Wrap the members in a LocalLB.PoolMember.MemberSessionStateSequence

sstate_seq = b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionStateSequence')

'item' is an attribute that maps to a list of 'Common.IPPortDefinition' objects.

sstate_seq.item = session_state_factory(b, members)

def disable_member(b, session_objects):

"""

Disable our members in the of session state

objects.

"""

try:

b.LocalLB.PoolMember.set_session_enabled_state(pool_names =

[POOL], session_states = [sstate_seq])

except Exception, e:

print e

sys.exit(1)

def enable_member(b, session_objects):

"""

Enable our members in the of session state

objects.

"""

Note how easy it is to simply 'toggle' the session state now that

we are dealing with object attributes.

for x in sstate_seq.item:

x.session_state = 'STATE_ENABLED'

try:

b.LocalLB.PoolMember.set_session_enabled_state(pool_names = [POOL],

session_states = [sstate_seq])

except Exception, e:

print e

sys.exit(1)

def add_member(b, members):

"""

"""

print repr(dir(b.LocalLB.Pool))

try:

b.LocalLB.Pool.add_member(pool_names = [POOL],

members = members)

except Exception, e:

print e

sys.exit(1)

def delete_member(b, session_objects):

"""

"""

print repr(dir(b.LocalLB.Pool))

try:

b.LocalLB.Pool.remove_member(pool_names = [POOL],

members = members)

except Exception, e:

print e

sys.exit(1)

if action == 'add':

Add an IP:PORT member to a pool

add_member(b, members)

Confirm pool list

res = b.LocalLB.PoolMember.get_session_enabled_state(pool_names = [POOL])

print "States: %s" % res

sys.exit(0)

elif action == 'delete':

Delete an IP:PORT member of a pool

delete_member(b, members)

Confirm pool list

res = b.LocalLB.PoolMember.get_session_enabled_state(pool_names = [POOL])

print "States: %s" % res

sys.exit(0)

else:

print "State: %s not defined" % action

sys.exit(1)

6 Replies

  • The full code (I snipped some stuff out that wasn't directly relevent) runs fine without error, but the pool member list isn't modified. So I must be doing something wrong with the add/remove api calls.

     

  • So now I have pool_objects which I construct using pool_factory... but now i'm getting complaints about suds and a reference to address:

     

    
    
    def pool_factory(b, members):
        '''
        '''
    
        pobj = []
        for x in members:
            ip,port = x.split(':')
            pmem = b.LocalLB.Pool.typefactory.create('Common.IPPortDefinition')
            pmem.address = ip
            pmem.port = int(port)
            pobj.append(pmem)
        return pobj
    
    pool_objects = pool_factory(b,members)
    
    def add_member(b, pool_objects):
        """
        """
        try:
           b.LocalLB.Pool.add_member(pool_names = [POOL],
                   members = pool_objects)
        except Exception, e:
            print e
            raise
            sys.exit(1)
    
    elif action == 'add':
         Add an IP:PORT member to a pool
        add_member(b, pool_objects)
         Confirm pool list
        res = b.LocalLB.PoolMember.get_session_enabled_state(pool_names = [POOL])
        print "States: %s" % res
        sys.exit(0)
    
    
    
    runtime gives
    
    No handlers could be found for logger "suds.client"
    Server raised fault: 'Could not find element by name: address'
    Traceback (most recent call last):
      File "modify_member.py", line 235, in 
        add_member(b, pool_objects)
      File "modify_member.py", line 185, in add_member
        members = [pool_objects])
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 539, in __call__
        return client.invoke(args, kwargs)
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 598, in invoke
        result = self.send(msg)
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 633, in send
        result = self.failed(binding, e)
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 684, in failed
        r, p = binding.get_fault(reply)
      File "/usr/lib/pymodules/python2.6/suds/bindings/binding.py", line 238, in get_fault
        raise WebFault(p, faultroot)
    suds.WebFault: Server raised fault: 'Could not find element by name: address'
     

     

  • So now I have pool_objects which I construct using pool_factory... but now i'm getting complaints about suds and a reference to address:

     

    
    
    def pool_factory(b, members):
        '''
        '''
    
        pobj = []
        for x in members:
            ip,port = x.split(':')
            pmem = b.LocalLB.Pool.typefactory.create('Common.IPPortDefinition')
            pmem.address = ip
            pmem.port = int(port)
            pobj.append(pmem)
        return pobj
    
    pool_objects = pool_factory(b,members)
    
    def add_member(b, pool_objects):
        """
        """
        try:
           b.LocalLB.Pool.add_member(pool_names = [POOL],
                   members = pool_objects)
        except Exception, e:
            print e
            raise
            sys.exit(1)
    
    elif action == 'add':
         Add an IP:PORT member to a pool
        add_member(b, pool_objects)
         Confirm pool list
        res = b.LocalLB.PoolMember.get_session_enabled_state(pool_names = [POOL])
        print "States: %s" % res
        sys.exit(0)
    
    
    
    runtime gives
    
    No handlers could be found for logger "suds.client"
    Server raised fault: 'Could not find element by name: address'
    Traceback (most recent call last):
      File "modify_member.py", line 235, in 
        add_member(b, pool_objects)
      File "modify_member.py", line 185, in add_member
        members = [pool_objects])
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 539, in __call__
        return client.invoke(args, kwargs)
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 598, in invoke
        result = self.send(msg)
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 633, in send
        result = self.failed(binding, e)
      File "/usr/lib/pymodules/python2.6/suds/client.py", line 684, in failed
        r, p = binding.get_fault(reply)
      File "/usr/lib/pymodules/python2.6/suds/bindings/binding.py", line 238, in get_fault
        raise WebFault(p, faultroot)
    suds.WebFault: Server raised fault: 'Could not find element by name: address'
     

     

    - Global variables, evil.

    - remove_member is deprecated, use remove_member_v2 for V11 F5

    - You pass global members into session_objects function parameter to delete_member... then you don't reference it. Why?

    - You pass global 'members' to "remove_member" API call. It's the wrong type -- you are supposed to pass a sequence of IPPortDefinition.

    I have a complete solution I've written for my current employer. Would love it if I could just post it but I don't have that freedom at this point. That being said, something like this works:

     

    
    
    def f5_build_address_port_seq(b, addressport):
        addressportseq = b.LocalLB.Pool.typefactory.create('Common.AddressPortSequence')
        addressportseq.item = addressport
        return addressportseq
    
    def f5_build_address_port(b, address, port):
        addressport = b.LocalLB.Pool.typefactory.create('Common.AddressPort')
        addressport.address = address
        addressport.port = port
        return addressport
    
    def f5_remove_pool_member_v11(b, poolname, address, port):
        addressport = f5_build_address_port(b, address, port)
        addressportseq = f5_build_address_port_seq(b, addressport)
        b.LocalLB.Pool.remove_member_v2(pool_names=[poolname], members=[addressportseq])
    
    

     

    Then you just run:

    f5_remove_pool_member_v11(b, poolname, address, port)

    As an aside, if I were doing this from scratch, I'd be using bigsuds and not pycontrol.

  • If I didn't mention it before, I'm extremely new to python, however I'm also building off existing (albeit bad) code. My comfort level with this language isn't that high at this point.

     

    Good notes on v11, but we're still working with v10 so the old deprecated api tree applies with add_member and remove_member; not sure if the v2 segments are compatible with v9 and v10 BigIPs.

     

    I'll review what you've posted and see where I can go from there. Thanks.

     

  • The parameter changes are minor. v11 uses addressport sequence, whereas pre-v11 uses ipportdefinition sequence.
  • Posted By mhite on 11/21/2012 11:14 AM

     

    - Global variables, evil.

     

    - remove_member is deprecated, use remove_member_v2 for V11 F5

     

    - You pass global members into session_objects function parameter to delete_member... then you don't reference it. Why?

     

    - You pass global 'members' to "remove_member" API call. It's the wrong type -- you are supposed to pass a sequence of IPPortDefinition.

     

     

    I have a complete solution I've written for my current employer. Would love it if I could just post it but I don't have that freedom at this point. That being said, something like this works:

     

     

     def f5_build_address_port_seq(b, addressport): addressportseq = b.LocalLB.Pool.typefactory.create('Common.AddressPortSequence') addressportseq.item = addressport return addressportseq def f5_build_address_port(b, address, port): addressport = b.LocalLB.Pool.typefactory.create('Common.AddressPort') addressport.address = address addressport.port = port return addressport def f5_remove_pool_member_v11(b, poolname, address, port): addressport = f5_build_address_port(b, address, port) addressportseq = f5_build_address_port_seq(b, addressport) b.LocalLB.Pool.remove_member_v2(pool_names=[poolname], members=[addressportseq]) 

     

     

    Then you just run:

     

     

    f5_remove_pool_member_v11(b, poolname, address, port)

     

     

    As an aside, if I were doing this from scratch, I'd be using bigsuds and not pycontrol.

     

    mhite,

     

    Thanks for your insights with the code snippets. I was able to patch/cobble together the rest of the script required to do the necessary operations for the moment.

     

    As I learn python more in-depth, I'm sure that I'll be able to craft much better code than that currently hacked upon; I don't like using other people's code for the reason that it inhibits my own learning, but deadlines are deadlines and I needed to get something out quick and most of the framework was there with the base script linked to above... just needed to bolt a few extra things on 😃