@ -1,6 +1,6 @@
#!/usr/bin/python
#!/usr/bin/python
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
# (c) 2013, Matt Hite <mhite@hotmail.com>
# (c) 2013, Matt Hite <mhite@hotmail.com>
#
#
# This file is part of Ansible
# This file is part of Ansible
@ -21,204 +21,212 @@
DOCUMENTATION = '''
DOCUMENTATION = '''
- - -
- - -
module : bigip_pool_member
module : bigip_pool_member
short_description : " Manages F5 BIG-IP LTM pool members "
short_description : Manages F5 BIG - IP LTM pool members
description :
description :
- " Manages F5 BIG-IP LTM pool members via iControl SOAP API "
- Manages F5 BIG - IP LTM pool members via iControl SOAP API
version_added : " 1.4 "
version_added : 1.4
author :
author :
- Matt Hite ( @mhite )
- Matt Hite ( @mhite )
- Tim Rupp ( @caphrim007 )
- Tim Rupp ( @caphrim007 )
notes :
notes :
- " Requires BIG-IP software version >= 11 "
- Requires BIG - IP software version > = 11
- " F5 developed module ' bigsuds ' required (see http://devcentral.f5.com) "
- F5 developed module ' bigsuds ' required ( see http : / / devcentral . f5 . com )
- " Best run as a local_action in your playbook "
- Best run as a local_action in your playbook
- " Supersedes bigip_pool for managing pool members "
- Supersedes bigip_pool for managing pool members
requirements :
requirements :
- bigsuds
- bigsuds
options :
options :
server :
server :
description :
description :
- BIG - IP host
- BIG - IP host
required : true
required : true
server_port :
server_port :
description :
description :
- BIG - IP server port
- BIG - IP server port
required : false
required : false
default : 443
default : 443
version_added : " 2.2 "
version_added : " 2.2 "
user :
user :
description :
description :
- BIG - IP username
- BIG - IP username
required : true
required : true
password :
password :
description :
description :
- BIG - IP password
- BIG - IP password
required : true
required : true
validate_certs :
validate_certs :
description :
description :
- If C ( no ) , SSL certificates will not be validated . This should only be used
- If C ( no ) , SSL certificates will not be validated . This should only be used
on personally controlled sites . Prior to 2.0 , this module would always
on personally controlled sites . Prior to 2.0 , this module would always
validate on python > = 2.7 .9 and never validate on python < = 2.7 .8
validate on python > = 2.7 .9 and never validate on python < = 2.7 .8
required : false
required : false
default : ' yes '
default : ' yes '
choices : [ ' yes ' , ' no ' ]
choices :
version_added : 2.0
- yes
state :
- no
description :
version_added : 2.0
- Pool member state
state :
required : true
description :
default : present
- Pool member state
choices : [ ' present ' , ' absent ' ]
required : true
session_state :
default : present
description :
choices :
- Set new session availability status for pool member
- present
version_added : " 2.0 "
- absent
required : false
session_state :
default : null
description :
choices : [ ' enabled ' , ' disabled ' ]
- Set new session availability status for pool member
monitor_state :
version_added : 2.0
description :
required : false
- Set monitor availability status for pool member
default : null
version_added : " 2.0 "
choices :
required : false
- enabled
default : null
- disabled
choices : [ ' enabled ' , ' disabled ' ]
monitor_state :
pool :
description :
description :
- Set monitor availability status for pool member
- Pool name . This pool must exist .
version_added : 2.0
required : true
required : false
partition :
default : null
description :
choices :
- Partition
- enabled
required : false
- disabled
default : ' Common '
pool :
host :
description :
description :
- Pool name . This pool must exist .
- Pool member IP
required : true
required : true
partition :
aliases : [ ' address ' , ' name ' ]
description :
port :
- Partition
description :
required : false
- Pool member port
default : ' Common '
required : true
host :
connection_limit :
description :
description :
- Pool member IP
- Pool member connection limit . Setting this to 0 disables the limit .
required : true
required : false
aliases :
default : null
- address
- name
port :
description :
description :
description :
- Pool member port
- Pool member description
required : true
required : false
connection_limit :
default : null
description :
rate_limit :
- Pool member connection limit . Setting this to 0 disables the limit .
description :
required : false
- Pool member rate limit ( connections - per - second ) . Setting this to 0 disables the limit .
default : null
required : false
description :
default : null
description :
ratio :
- Pool member description
description :
required : false
- Pool member ratio weight . Valid values range from 1 through 100. New pool members - - unless overriden with this value - - default to 1.
default : null
required : false
rate_limit :
default : null
description :
preserve_node :
- Pool member rate limit ( connections - per - second ) . Setting this to 0
description :
disables the limit .
- When state is absent and the pool member is no longer referenced in other pools , the default behavior removes the unused node object . Setting this to ' yes ' disables this behavior .
required : false
required : false
default : null
default : ' no '
ratio :
choices : [ ' yes ' , ' no ' ]
description :
version_added : 2.1
- Pool member ratio weight . Valid values range from 1 through 100.
New pool members - - unless overriden with this value - - default
to 1.
required : false
default : null
preserve_node :
description :
- When state is absent and the pool member is no longer referenced
in other pools , the default behavior removes the unused node
o bject . Setting this to ' yes ' disables this behavior .
required : false
default : ' no '
choices :
- yes
- no
version_added : 2.1
'''
'''
EXAMPLES = '''
EXAMPLES = '''
- name : Add pool member
## playbook task examples:
bigip_pool_member :
server : " lb.mydomain.com "
- - -
user : " admin "
# file bigip-test.yml
password : " secret "
# ...
state : " present "
- hosts : bigip - test
pool : " my-pool "
tasks :
partition : " Common "
- name : Add pool member
host : " {{ ansible_default_ipv4[ " address " ] }} "
local_action : >
port : 80
bigip_pool_member
description : " web server "
server = lb . mydomain . com
connection_limit : 100
user = admin
rate_limit : 50
password = mysecret
ratio : 2
state = present
delegate_to : localhost
pool = matthite - pool
partition = matthite
- name : Modify pool member ratio and description
host = " {{ ansible_default_ipv4[ " address " ] }} "
bigip_pool_member :
port = 80
server : " lb.mydomain.com "
description = " web server "
user : " admin "
connection_limit = 100
password : " secret "
rate_limit = 50
state : " present "
ratio = 2
pool : " my-pool "
partition : " Common "
- name : Modify pool member ratio and description
host : " {{ ansible_default_ipv4[ " address " ] }} "
local_action : >
port : 80
bigip_pool_member
ratio : 1
server = lb . mydomain . com
description : " nginx server "
user = admin
delegate_to : localhost
password = mysecret
state = present
- name : Remove pool member from pool
pool = matthite - pool
bigip_pool_member :
partition = matthite
server : " lb.mydomain.com "
host = " {{ ansible_default_ipv4[ " address " ] }} "
user : " admin "
port = 80
password : " secret "
ratio = 1
state : " absent "
description = " nginx server "
pool : " my-pool "
partition : " Common "
- name : Remove pool member from pool
host : " {{ ansible_default_ipv4[ " address " ] }} "
local_action : >
port : 80
bigip_pool_member
delegate_to : localhost
server = lb . mydomain . com
user = admin
password = mysecret
# The BIG-IP GUI doesn't map directly to the API calls for "Pool ->
state = absent
# Members -> State". The following states map to API monitor
pool = matthite - pool
# and session states.
partition = matthite
#
host = " {{ ansible_default_ipv4[ " address " ] }} "
# Enabled (all traffic allowed):
port = 80
# monitor_state=enabled, session_state=enabled
# Disabled (only persistent or active connections allowed):
# monitor_state=enabled, session_state=disabled
# The BIG-IP GUI doesn't map directly to the API calls for "Pool ->
# Forced offline (only active connections allowed):
# Members -> State". The following states map to API monitor
# monitor_state=disabled, session_state=disabled
# and session states.
#
#
# See https://devcentral.f5.com/questions/icontrol-equivalent-call-for-b-node-down
# Enabled (all traffic allowed):
# monitor_state=enabled, session_state=enabled
- name : Force pool member offline
# Disabled (only persistent or active connections allowed):
bigip_pool_member :
# monitor_state=enabled, session_state=disabled
server : " lb.mydomain.com "
# Forced offline (only active connections allowed):
user : " admin "
# monitor_state=disabled, session_state=disabled
password : " secret "
#
state : " present "
# See https://devcentral.f5.com/questions/icontrol-equivalent-call-for-b-node-down
session_state : " disabled "
monitor_state : " disabled "
- name : Force pool member offline
pool : " my-pool "
local_action : >
partition : " Common "
bigip_pool_member
host : " {{ ansible_default_ipv4[ " address " ] }} "
server = lb . mydomain . com
port : 80
user = admin
delegate_to : localhost
password = mysecret
state = present
session_state = disabled
monitor_state = disabled
pool = matthite - pool
partition = matthite
host = " {{ ansible_default_ipv4[ " address " ] }} "
port = 80
'''
'''
def pool_exists ( api , pool ) :
def pool_exists ( api , pool ) :
# hack to determine if pool exists
# hack to determine if pool exists
result = False
result = False
try :
try :
api . LocalLB . Pool . get_object_status ( pool_names = [ pool ] )
api . LocalLB . Pool . get_object_status ( pool_names = [ pool ] )
result = True
result = True
except bigsuds . OperationFailed , e :
except bigsuds . OperationFailed as e :
if " was not found " in str ( e ) :
if " was not found " in str ( e ) :
result = False
result = False
else :
else :
@ -226,6 +234,7 @@ def pool_exists(api, pool):
raise
raise
return result
return result
def member_exists ( api , pool , address , port ) :
def member_exists ( api , pool , address , port ) :
# hack to determine if member exists
# hack to determine if member exists
result = False
result = False
@ -234,7 +243,7 @@ def member_exists(api, pool, address, port):
api . LocalLB . Pool . get_member_object_status ( pool_names = [ pool ] ,
api . LocalLB . Pool . get_member_object_status ( pool_names = [ pool ] ,
members = [ members ] )
members = [ members ] )
result = True
result = True
except bigsuds . OperationFailed , e :
except bigsuds . OperationFailed as e :
if " was not found " in str ( e ) :
if " was not found " in str ( e ) :
result = False
result = False
else :
else :
@ -242,12 +251,13 @@ def member_exists(api, pool, address, port):
raise
raise
return result
return result
def delete_node_address ( api , address ) :
def delete_node_address ( api , address ) :
result = False
result = False
try :
try :
api . LocalLB . NodeAddressV2 . delete_node_address ( nodes = [ address ] )
api . LocalLB . NodeAddressV2 . delete_node_address ( nodes = [ address ] )
result = True
result = True
except bigsuds . OperationFailed , e :
except bigsuds . OperationFailed as e :
if " is referenced by a member of pool " in str ( e ) :
if " is referenced by a member of pool " in str ( e ) :
result = False
result = False
else :
else :
@ -255,96 +265,157 @@ def delete_node_address(api, address):
raise
raise
return result
return result
def remove_pool_member ( api , pool , address , port ) :
def remove_pool_member ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
api . LocalLB . Pool . remove_member_v2 ( pool_names = [ pool ] , members = [ members ] )
api . LocalLB . Pool . remove_member_v2 (
pool_names = [ pool ] ,
members = [ members ]
)
def add_pool_member ( api , pool , address , port ) :
def add_pool_member ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
api . LocalLB . Pool . add_member_v2 ( pool_names = [ pool ] , members = [ members ] )
api . LocalLB . Pool . add_member_v2 (
pool_names = [ pool ] ,
members = [ members ]
)
def get_connection_limit ( api , pool , address , port ) :
def get_connection_limit ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
result = api . LocalLB . Pool . get_member_connection_limit ( pool_names = [ pool ] , members = [ members ] ) [ 0 ] [ 0 ]
result = api . LocalLB . Pool . get_member_connection_limit (
pool_names = [ pool ] ,
members = [ members ]
) [ 0 ] [ 0 ]
return result
return result
def set_connection_limit ( api , pool , address , port , limit ) :
def set_connection_limit ( api , pool , address , port , limit ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
api . LocalLB . Pool . set_member_connection_limit ( pool_names = [ pool ] , members = [ members ] , limits = [ [ limit ] ] )
api . LocalLB . Pool . set_member_connection_limit (
pool_names = [ pool ] ,
members = [ members ] ,
limits = [ [ limit ] ]
)
def get_description ( api , pool , address , port ) :
def get_description ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
result = api . LocalLB . Pool . get_member_description ( pool_names = [ pool ] , members = [ members ] ) [ 0 ] [ 0 ]
result = api . LocalLB . Pool . get_member_description (
pool_names = [ pool ] ,
members = [ members ]
) [ 0 ] [ 0 ]
return result
return result
def set_description ( api , pool , address , port , description ) :
def set_description ( api , pool , address , port , description ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
api . LocalLB . Pool . set_member_description ( pool_names = [ pool ] , members = [ members ] , descriptions = [ [ description ] ] )
api . LocalLB . Pool . set_member_description (
pool_names = [ pool ] ,
members = [ members ] ,
descriptions = [ [ description ] ]
)
def get_rate_limit ( api , pool , address , port ) :
def get_rate_limit ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
result = api . LocalLB . Pool . get_member_rate_limit ( pool_names = [ pool ] , members = [ members ] ) [ 0 ] [ 0 ]
result = api . LocalLB . Pool . get_member_rate_limit (
pool_names = [ pool ] ,
members = [ members ]
) [ 0 ] [ 0 ]
return result
return result
def set_rate_limit ( api , pool , address , port , limit ) :
def set_rate_limit ( api , pool , address , port , limit ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
api . LocalLB . Pool . set_member_rate_limit ( pool_names = [ pool ] , members = [ members ] , limits = [ [ limit ] ] )
api . LocalLB . Pool . set_member_rate_limit (
pool_names = [ pool ] ,
members = [ members ] ,
limits = [ [ limit ] ]
)
def get_ratio ( api , pool , address , port ) :
def get_ratio ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
result = api . LocalLB . Pool . get_member_ratio ( pool_names = [ pool ] , members = [ members ] ) [ 0 ] [ 0 ]
result = api . LocalLB . Pool . get_member_ratio (
pool_names = [ pool ] ,
members = [ members ]
) [ 0 ] [ 0 ]
return result
return result
def set_ratio ( api , pool , address , port , ratio ) :
def set_ratio ( api , pool , address , port , ratio ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
api . LocalLB . Pool . set_member_ratio ( pool_names = [ pool ] , members = [ members ] , ratios = [ [ ratio ] ] )
api . LocalLB . Pool . set_member_ratio (
pool_names = [ pool ] ,
members = [ members ] ,
ratios = [ [ ratio ] ]
)
def set_member_session_enabled_state ( api , pool , address , port , session_state ) :
def set_member_session_enabled_state ( api , pool , address , port , session_state ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
session_state = [ " STATE_ %s " % session_state . strip ( ) . upper ( ) ]
session_state = [ " STATE_ %s " % session_state . strip ( ) . upper ( ) ]
api . LocalLB . Pool . set_member_session_enabled_state ( pool_names = [ pool ] , members = [ members ] , session_states = [ session_state ] )
api . LocalLB . Pool . set_member_session_enabled_state (
pool_names = [ pool ] ,
members = [ members ] ,
session_states = [ session_state ]
)
def get_member_session_status ( api , pool , address , port ) :
def get_member_session_status ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
result = api . LocalLB . Pool . get_member_session_status ( pool_names = [ pool ] , members = [ members ] ) [ 0 ] [ 0 ]
result = api . LocalLB . Pool . get_member_session_status (
pool_names = [ pool ] ,
members = [ members ]
) [ 0 ] [ 0 ]
result = result . split ( " SESSION_STATUS_ " ) [ - 1 ] . lower ( )
result = result . split ( " SESSION_STATUS_ " ) [ - 1 ] . lower ( )
return result
return result
def set_member_monitor_state ( api , pool , address , port , monitor_state ) :
def set_member_monitor_state ( api , pool , address , port , monitor_state ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
monitor_state = [ " STATE_ %s " % monitor_state . strip ( ) . upper ( ) ]
monitor_state = [ " STATE_ %s " % monitor_state . strip ( ) . upper ( ) ]
api . LocalLB . Pool . set_member_monitor_state ( pool_names = [ pool ] , members = [ members ] , monitor_states = [ monitor_state ] )
api . LocalLB . Pool . set_member_monitor_state (
pool_names = [ pool ] ,
members = [ members ] ,
monitor_states = [ monitor_state ]
)
def get_member_monitor_status ( api , pool , address , port ) :
def get_member_monitor_status ( api , pool , address , port ) :
members = [ { ' address ' : address , ' port ' : port } ]
members = [ { ' address ' : address , ' port ' : port } ]
result = api . LocalLB . Pool . get_member_monitor_status ( pool_names = [ pool ] , members = [ members ] ) [ 0 ] [ 0 ]
result = api . LocalLB . Pool . get_member_monitor_status (
pool_names = [ pool ] ,
members = [ members ]
) [ 0 ] [ 0 ]
result = result . split ( " MONITOR_STATUS_ " ) [ - 1 ] . lower ( )
result = result . split ( " MONITOR_STATUS_ " ) [ - 1 ] . lower ( )
return result
return result
def main ( ) :
def main ( ) :
argument_spec = f5_argument_spec ( )
argument_spec = f5_argument_spec ( )
argument_spec . update ( dict (
session_state = dict ( type = ' str ' , choices = [ ' enabled ' , ' disabled ' ] ) ,
meta_args = dict (
monitor_state = dict ( type = ' str ' , choices = [ ' enabled ' , ' disabled ' ] ) ,
session_state = dict ( type = ' str ' , choices = [ ' enabled ' , ' disabled ' ] ) ,
pool = dict ( type = ' str ' , required = True ) ,
monitor_state = dict ( type = ' str ' , choices = [ ' enabled ' , ' disabled ' ] ) ,
host = dict ( type = ' str ' , required = True , aliases = [ ' address ' , ' name ' ] ) ,
pool = dict ( type = ' str ' , required = True ) ,
port = dict ( type = ' int ' , required = True ) ,
host = dict ( type = ' str ' , required = True , aliases = [ ' address ' , ' name ' ] ) ,
connection_limit = dict ( type = ' int ' ) ,
port = dict ( type = ' int ' , required = True ) ,
description = dict ( type = ' str ' ) ,
connection_limit = dict ( type = ' int ' ) ,
rate_limit = dict ( type = ' int ' ) ,
description = dict ( type = ' str ' ) ,
ratio = dict ( type = ' int ' ) ,
rate_limit = dict ( type = ' int ' ) ,
preserve_node = dict ( type = ' bool ' , default = False )
ratio = dict ( type = ' int ' ) ,
)
preserve_node = dict ( type = ' bool ' , default = False )
)
)
argument_spec . update ( meta_args )
module = AnsibleModule (
module = AnsibleModule (
argument_spec = argument_spec ,
argument_spec = argument_spec ,
supports_check_mode = True
supports_check_mode = True
)
)
if not bigsuds_found :
module . fail_json ( msg = " the python bigsuds module is required " )
if module . params [ ' validate_certs ' ] :
if module . params [ ' validate_certs ' ] :
import ssl
import ssl
if not hasattr ( ssl , ' SSLContext ' ) :
if not hasattr ( ssl , ' SSLContext ' ) :
@ -370,9 +441,6 @@ def main():
port = module . params [ ' port ' ]
port = module . params [ ' port ' ]
preserve_node = module . params [ ' preserve_node ' ]
preserve_node = module . params [ ' preserve_node ' ]
# sanity check user supplied values
if ( host and port is None ) or ( port is not None and not host ) :
if ( host and port is None ) or ( port is not None and not host ) :
module . fail_json ( msg = " both host and port must be supplied " )
module . fail_json ( msg = " both host and port must be supplied " )
@ -453,12 +521,11 @@ def main():
set_member_monitor_state ( api , pool , address , port , monitor_state )
set_member_monitor_state ( api , pool , address , port , monitor_state )
result = { ' changed ' : True }
result = { ' changed ' : True }
except Exception , e :
except Exception as e :
module . fail_json ( msg = " received exception: %s " % e )
module . fail_json ( msg = " received exception: %s " % e )
module . exit_json ( * * result )
module . exit_json ( * * result )
# import module snippets
from ansible . module_utils . basic import *
from ansible . module_utils . basic import *
from ansible . module_utils . f5 import *
from ansible . module_utils . f5 import *