mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-07 22:02:50 +00:00
Fix rename error.
This commit is contained in:
committed by
Matt Clay
parent
55b41340fc
commit
ee87304fb8
0
lib/ansible/modules/extras/network/f5/__init__.py
Normal file
0
lib/ansible/modules/extras/network/f5/__init__.py
Normal file
1670
lib/ansible/modules/extras/network/f5/bigip_facts.py
Executable file
1670
lib/ansible/modules/extras/network/f5/bigip_facts.py
Executable file
File diff suppressed because it is too large
Load Diff
464
lib/ansible/modules/extras/network/f5/bigip_monitor_http.py
Normal file
464
lib/ansible/modules/extras/network/f5/bigip_monitor_http.py
Normal file
@@ -0,0 +1,464 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, serge van Ginderachter <serge@vanginderachter.be>
|
||||
# based on Matt Hite's bigip_pool module
|
||||
# (c) 2013, Matt Hite <mhite@hotmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: bigip_monitor_http
|
||||
short_description: "Manages F5 BIG-IP LTM http monitors"
|
||||
description:
|
||||
- "Manages F5 BIG-IP LTM monitors via iControl SOAP API"
|
||||
version_added: "1.4"
|
||||
author: Serge van Ginderachter
|
||||
notes:
|
||||
- "Requires BIG-IP software version >= 11"
|
||||
- "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
|
||||
- "Best run as a local_action in your playbook"
|
||||
- "Monitor API documentation: https://devcentral.f5.com/wiki/iControl.LocalLB__Monitor.ashx"
|
||||
requirements:
|
||||
- bigsuds
|
||||
options:
|
||||
server:
|
||||
description:
|
||||
- BIG-IP host
|
||||
required: true
|
||||
default: null
|
||||
user:
|
||||
description:
|
||||
- BIG-IP username
|
||||
required: true
|
||||
default: null
|
||||
password:
|
||||
description:
|
||||
- BIG-IP password
|
||||
required: true
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- Monitor state
|
||||
required: false
|
||||
default: 'present'
|
||||
choices: ['present', 'absent']
|
||||
name:
|
||||
description:
|
||||
- Monitor name
|
||||
required: true
|
||||
default: null
|
||||
aliases: ['monitor']
|
||||
partition:
|
||||
description:
|
||||
- Partition for the monitor
|
||||
required: false
|
||||
default: 'Common'
|
||||
parent:
|
||||
description:
|
||||
- The parent template of this monitor template
|
||||
required: false
|
||||
default: 'http'
|
||||
parent_partition:
|
||||
description:
|
||||
- Partition for the parent monitor
|
||||
required: false
|
||||
default: 'Common'
|
||||
send:
|
||||
description:
|
||||
- The send string for the monitor call
|
||||
required: true
|
||||
default: none
|
||||
receive:
|
||||
description:
|
||||
- The receive string for the monitor call
|
||||
required: true
|
||||
default: none
|
||||
receive_disable:
|
||||
description:
|
||||
- The receive disable string for the monitor call
|
||||
required: true
|
||||
default: none
|
||||
ip:
|
||||
description:
|
||||
- IP address part of the ipport definition. The default API setting
|
||||
is "0.0.0.0".
|
||||
required: false
|
||||
default: none
|
||||
port:
|
||||
description:
|
||||
- port address part op the ipport definition. The default API
|
||||
setting is 0.
|
||||
required: false
|
||||
default: none
|
||||
interval:
|
||||
description:
|
||||
- The interval specifying how frequently the monitor instance
|
||||
of this template will run. By default, this interval is used for up and
|
||||
down states. The default API setting is 5.
|
||||
required: false
|
||||
default: none
|
||||
timeout:
|
||||
description:
|
||||
- The number of seconds in which the node or service must respond to
|
||||
the monitor request. If the target responds within the set time
|
||||
period, it is considered up. If the target does not respond within
|
||||
the set time period, it is considered down. You can change this
|
||||
number to any number you want, however, it should be 3 times the
|
||||
interval number of seconds plus 1 second. The default API setting
|
||||
is 16.
|
||||
required: false
|
||||
default: none
|
||||
time_until_up:
|
||||
description:
|
||||
- Specifies the amount of time in seconds after the first successful
|
||||
response before a node will be marked up. A value of 0 will cause a
|
||||
node to be marked up immediately after a valid response is received
|
||||
from the node. The default API setting is 0.
|
||||
required: false
|
||||
default: none
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: BIGIP F5 | Create HTTP Monitor
|
||||
local_action:
|
||||
module: bigip_monitor_http
|
||||
state: present
|
||||
server: "{{ f5server }}"
|
||||
user: "{{ f5user }}"
|
||||
password: "{{ f5password }}"
|
||||
name: "{{ item.monitorname }}"
|
||||
send: "{{ item.send }}"
|
||||
receive: "{{ item.receive }}"
|
||||
with_items: f5monitors
|
||||
- name: BIGIP F5 | Remove HTTP Monitor
|
||||
local_action:
|
||||
module: bigip_monitor_http
|
||||
state: absent
|
||||
server: "{{ f5server }}"
|
||||
user: "{{ f5user }}"
|
||||
password: "{{ f5password }}"
|
||||
name: "{{ monitorname }}"
|
||||
'''
|
||||
|
||||
try:
|
||||
import bigsuds
|
||||
except ImportError:
|
||||
bigsuds_found = False
|
||||
else:
|
||||
bigsuds_found = True
|
||||
|
||||
TEMPLATE_TYPE = 'TTYPE_HTTP'
|
||||
DEFAULT_PARENT_TYPE = 'http'
|
||||
|
||||
|
||||
# ===========================================
|
||||
# bigip_monitor module generic methods.
|
||||
# these should be re-useable for other monitor types
|
||||
#
|
||||
|
||||
def bigip_api(bigip, user, password):
|
||||
|
||||
api = bigsuds.BIGIP(hostname=bigip, username=user, password=password)
|
||||
return api
|
||||
|
||||
|
||||
def check_monitor_exists(module, api, monitor, parent):
|
||||
|
||||
# hack to determine if monitor exists
|
||||
result = False
|
||||
try:
|
||||
ttype = api.LocalLB.Monitor.get_template_type(template_names=[monitor])[0]
|
||||
parent2 = api.LocalLB.Monitor.get_parent_template(template_names=[monitor])[0]
|
||||
if ttype == TEMPLATE_TYPE and parent == parent2:
|
||||
result = True
|
||||
else:
|
||||
module.fail_json(msg='Monitor already exists, but has a different type (%s) or parent(%s)' % (ttype, parent))
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
|
||||
def create_monitor(api, monitor, template_attributes):
|
||||
|
||||
try:
|
||||
api.LocalLB.Monitor.create_template(templates=[{'template_name': monitor, 'template_type': TEMPLATE_TYPE}], template_attributes=[template_attributes])
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "already exists" in str(e):
|
||||
return False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def delete_monitor(api, monitor):
|
||||
|
||||
try:
|
||||
api.LocalLB.Monitor.delete_template(template_names=[monitor])
|
||||
except bigsuds.OperationFailed, e:
|
||||
# maybe it was deleted since we checked
|
||||
if "was not found" in str(e):
|
||||
return False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def check_string_property(api, monitor, str_property):
|
||||
|
||||
try:
|
||||
return str_property == api.LocalLB.Monitor.get_template_string_property([monitor], [str_property['type']])[0]
|
||||
except bigsuds.OperationFailed, e:
|
||||
# happens in check mode if not created yet
|
||||
if "was not found" in str(e):
|
||||
return True
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
|
||||
|
||||
def set_string_property(api, monitor, str_property):
|
||||
|
||||
api.LocalLB.Monitor.set_template_string_property(template_names=[monitor], values=[str_property])
|
||||
|
||||
|
||||
def check_integer_property(api, monitor, int_property):
|
||||
|
||||
try:
|
||||
return int_property == api.LocalLB.Monitor.get_template_integer_property([monitor], [int_property['type']])[0]
|
||||
except bigsuds.OperationFailed, e:
|
||||
# happens in check mode if not created yet
|
||||
if "was not found" in str(e):
|
||||
return True
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
|
||||
|
||||
|
||||
def set_integer_property(api, monitor, int_property):
|
||||
|
||||
api.LocalLB.Monitor.set_template_int_property(template_names=[monitor], values=[int_property])
|
||||
|
||||
|
||||
def update_monitor_properties(api, module, monitor, template_string_properties, template_integer_properties):
|
||||
|
||||
changed = False
|
||||
for str_property in template_string_properties:
|
||||
if str_property['value'] is not None and not check_string_property(api, monitor, str_property):
|
||||
if not module.check_mode:
|
||||
set_string_property(api, monitor, str_property)
|
||||
changed = True
|
||||
for int_property in template_integer_properties:
|
||||
if int_property['value'] is not None and not check_integer_property(api, monitor, int_property):
|
||||
if not module.check_mode:
|
||||
set_integer_property(api, monitor, int_property)
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
def get_ipport(api, monitor):
|
||||
|
||||
return api.LocalLB.Monitor.get_template_destination(template_names=[monitor])[0]
|
||||
|
||||
|
||||
def set_ipport(api, monitor, ipport):
|
||||
|
||||
try:
|
||||
api.LocalLB.Monitor.set_template_destination(template_names=[monitor], destinations=[ipport])
|
||||
return True, ""
|
||||
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "Cannot modify the address type of monitor" in str(e):
|
||||
return False, "Cannot modify the address type of monitor if already assigned to a pool."
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
|
||||
# ===========================================
|
||||
# main loop
|
||||
#
|
||||
# writing a module for other monitor types should
|
||||
# only need an updated main() (and monitor specific functions)
|
||||
|
||||
def main():
|
||||
|
||||
# begin monitor specific stuff
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
server = dict(required=True),
|
||||
user = dict(required=True),
|
||||
password = dict(required=True),
|
||||
partition = dict(default='Common'),
|
||||
state = dict(default='present', choices=['present', 'absent']),
|
||||
name = dict(required=True),
|
||||
parent = dict(default=DEFAULT_PARENT_TYPE),
|
||||
parent_partition = dict(default='Common'),
|
||||
send = dict(required=False),
|
||||
receive = dict(required=False),
|
||||
receive_disable = dict(required=False),
|
||||
ip = dict(required=False),
|
||||
port = dict(required=False, type='int'),
|
||||
interval = dict(required=False, type='int'),
|
||||
timeout = dict(required=False, type='int'),
|
||||
time_until_up = dict(required=False, type='int', default=0)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
server = module.params['server']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
partition = module.params['partition']
|
||||
parent_partition = module.params['parent_partition']
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
parent = "/%s/%s" % (parent_partition, module.params['parent'])
|
||||
monitor = "/%s/%s" % (partition, name)
|
||||
send = module.params['send']
|
||||
receive = module.params['receive']
|
||||
receive_disable = module.params['receive_disable']
|
||||
ip = module.params['ip']
|
||||
port = module.params['port']
|
||||
interval = module.params['interval']
|
||||
timeout = module.params['timeout']
|
||||
time_until_up = module.params['time_until_up']
|
||||
|
||||
# end monitor specific stuff
|
||||
|
||||
if not bigsuds_found:
|
||||
module.fail_json(msg="the python bigsuds module is required")
|
||||
api = bigip_api(server, user, password)
|
||||
monitor_exists = check_monitor_exists(module, api, monitor, parent)
|
||||
|
||||
|
||||
# ipport is a special setting
|
||||
if monitor_exists: # make sure to not update current settings if not asked
|
||||
cur_ipport = get_ipport(api, monitor)
|
||||
if ip is None:
|
||||
ip = cur_ipport['ipport']['address']
|
||||
if port is None:
|
||||
port = cur_ipport['ipport']['port']
|
||||
else: # use API defaults if not defined to create it
|
||||
if interval is None:
|
||||
interval = 5
|
||||
if timeout is None:
|
||||
timeout = 16
|
||||
if ip is None:
|
||||
ip = '0.0.0.0'
|
||||
if port is None:
|
||||
port = 0
|
||||
if send is None:
|
||||
send = ''
|
||||
if receive is None:
|
||||
receive = ''
|
||||
if receive_disable is None:
|
||||
receive_disable = ''
|
||||
|
||||
# define and set address type
|
||||
if ip == '0.0.0.0' and port == 0:
|
||||
address_type = 'ATYPE_STAR_ADDRESS_STAR_PORT'
|
||||
elif ip == '0.0.0.0' and port != 0:
|
||||
address_type = 'ATYPE_STAR_ADDRESS_EXPLICIT_PORT'
|
||||
elif ip != '0.0.0.0' and port != 0:
|
||||
address_type = 'ATYPE_EXPLICIT_ADDRESS_EXPLICIT_PORT'
|
||||
else:
|
||||
address_type = 'ATYPE_UNSET'
|
||||
|
||||
ipport = {'address_type': address_type,
|
||||
'ipport': {'address': ip,
|
||||
'port': port}}
|
||||
|
||||
template_attributes = {'parent_template': parent,
|
||||
'interval': interval,
|
||||
'timeout': timeout,
|
||||
'dest_ipport': ipport,
|
||||
'is_read_only': False,
|
||||
'is_directly_usable': True}
|
||||
|
||||
# monitor specific stuff
|
||||
template_string_properties = [{'type': 'STYPE_SEND',
|
||||
'value': send},
|
||||
{'type': 'STYPE_RECEIVE',
|
||||
'value': receive},
|
||||
{'type': 'STYPE_RECEIVE_DRAIN',
|
||||
'value': receive_disable}]
|
||||
|
||||
template_integer_properties = [{'type': 'ITYPE_INTERVAL',
|
||||
'value': interval},
|
||||
{'type': 'ITYPE_TIMEOUT',
|
||||
'value': timeout},
|
||||
{'type': 'ITYPE_TIME_UNTIL_UP',
|
||||
'value': time_until_up}]
|
||||
|
||||
# main logic, monitor generic
|
||||
|
||||
try:
|
||||
result = {'changed': False} # default
|
||||
|
||||
|
||||
if state == 'absent':
|
||||
if monitor_exists:
|
||||
if not module.check_mode:
|
||||
# possible race condition if same task
|
||||
# on other node deleted it first
|
||||
result['changed'] |= delete_monitor(api, monitor)
|
||||
else:
|
||||
result['changed'] |= True
|
||||
|
||||
else: # state present
|
||||
## check for monitor itself
|
||||
if not monitor_exists: # create it
|
||||
if not module.check_mode:
|
||||
# again, check changed status here b/c race conditions
|
||||
# if other task already created it
|
||||
result['changed'] |= create_monitor(api, monitor, template_attributes)
|
||||
else:
|
||||
result['changed'] |= True
|
||||
|
||||
## check for monitor parameters
|
||||
# whether it already existed, or was just created, now update
|
||||
# the update functions need to check for check mode but
|
||||
# cannot update settings if it doesn't exist which happens in check mode
|
||||
result['changed'] |= update_monitor_properties(api, module, monitor,
|
||||
template_string_properties,
|
||||
template_integer_properties)
|
||||
|
||||
# we just have to update the ipport if monitor already exists and it's different
|
||||
if monitor_exists and cur_ipport != ipport:
|
||||
set_ipport(api, monitor, ipport)
|
||||
result['changed'] |= True
|
||||
#else: monitor doesn't exist (check mode) or ipport is already ok
|
||||
|
||||
|
||||
except Exception, e:
|
||||
module.fail_json(msg="received exception: %s" % e)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
489
lib/ansible/modules/extras/network/f5/bigip_monitor_tcp.py
Normal file
489
lib/ansible/modules/extras/network/f5/bigip_monitor_tcp.py
Normal file
@@ -0,0 +1,489 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, serge van Ginderachter <serge@vanginderachter.be>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: bigip_monitor_tcp
|
||||
short_description: "Manages F5 BIG-IP LTM tcp monitors"
|
||||
description:
|
||||
- "Manages F5 BIG-IP LTM tcp monitors via iControl SOAP API"
|
||||
version_added: "1.4"
|
||||
author: Serge van Ginderachter
|
||||
notes:
|
||||
- "Requires BIG-IP software version >= 11"
|
||||
- "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
|
||||
- "Best run as a local_action in your playbook"
|
||||
- "Monitor API documentation: https://devcentral.f5.com/wiki/iControl.LocalLB__Monitor.ashx"
|
||||
requirements:
|
||||
- bigsuds
|
||||
options:
|
||||
server:
|
||||
description:
|
||||
- BIG-IP host
|
||||
required: true
|
||||
default: null
|
||||
user:
|
||||
description:
|
||||
- BIG-IP username
|
||||
required: true
|
||||
default: null
|
||||
password:
|
||||
description:
|
||||
- BIG-IP password
|
||||
required: true
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- Monitor state
|
||||
required: false
|
||||
default: 'present'
|
||||
choices: ['present', 'absent']
|
||||
name:
|
||||
description:
|
||||
- Monitor name
|
||||
required: true
|
||||
default: null
|
||||
aliases: ['monitor']
|
||||
partition:
|
||||
description:
|
||||
- Partition for the monitor
|
||||
required: false
|
||||
default: 'Common'
|
||||
type:
|
||||
description:
|
||||
- The template type of this monitor template
|
||||
required: false
|
||||
default: 'tcp'
|
||||
choices: [ 'TTYPE_TCP', 'TTYPE_TCP_ECHO', 'TTYPE_TCP_HALF_OPEN']
|
||||
parent:
|
||||
description:
|
||||
- The parent template of this monitor template
|
||||
required: false
|
||||
default: 'tcp'
|
||||
choices: [ 'tcp', 'tcp_echo', 'tcp_half_open']
|
||||
parent_partition:
|
||||
description:
|
||||
- Partition for the parent monitor
|
||||
required: false
|
||||
default: 'Common'
|
||||
send:
|
||||
description:
|
||||
- The send string for the monitor call
|
||||
required: true
|
||||
default: none
|
||||
receive:
|
||||
description:
|
||||
- The receive string for the monitor call
|
||||
required: true
|
||||
default: none
|
||||
ip:
|
||||
description:
|
||||
- IP address part of the ipport definition. The default API setting
|
||||
is "0.0.0.0".
|
||||
required: false
|
||||
default: none
|
||||
port:
|
||||
description:
|
||||
- port address part op the ipport definition. The default API
|
||||
setting is 0.
|
||||
required: false
|
||||
default: none
|
||||
interval:
|
||||
description:
|
||||
- The interval specifying how frequently the monitor instance
|
||||
of this template will run. By default, this interval is used for up and
|
||||
down states. The default API setting is 5.
|
||||
required: false
|
||||
default: none
|
||||
timeout:
|
||||
description:
|
||||
- The number of seconds in which the node or service must respond to
|
||||
the monitor request. If the target responds within the set time
|
||||
period, it is considered up. If the target does not respond within
|
||||
the set time period, it is considered down. You can change this
|
||||
number to any number you want, however, it should be 3 times the
|
||||
interval number of seconds plus 1 second. The default API setting
|
||||
is 16.
|
||||
required: false
|
||||
default: none
|
||||
time_until_up:
|
||||
description:
|
||||
- Specifies the amount of time in seconds after the first successful
|
||||
response before a node will be marked up. A value of 0 will cause a
|
||||
node to be marked up immediately after a valid response is received
|
||||
from the node. The default API setting is 0.
|
||||
required: false
|
||||
default: none
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
- name: BIGIP F5 | Create TCP Monitor
|
||||
local_action:
|
||||
module: bigip_monitor_tcp
|
||||
state: present
|
||||
server: "{{ f5server }}"
|
||||
user: "{{ f5user }}"
|
||||
password: "{{ f5password }}"
|
||||
name: "{{ item.monitorname }}"
|
||||
type: tcp
|
||||
send: "{{ item.send }}"
|
||||
receive: "{{ item.receive }}"
|
||||
with_items: f5monitors-tcp
|
||||
- name: BIGIP F5 | Create TCP half open Monitor
|
||||
local_action:
|
||||
module: bigip_monitor_tcp
|
||||
state: present
|
||||
server: "{{ f5server }}"
|
||||
user: "{{ f5user }}"
|
||||
password: "{{ f5password }}"
|
||||
name: "{{ item.monitorname }}"
|
||||
type: tcp
|
||||
send: "{{ item.send }}"
|
||||
receive: "{{ item.receive }}"
|
||||
with_items: f5monitors-halftcp
|
||||
- name: BIGIP F5 | Remove TCP Monitor
|
||||
local_action:
|
||||
module: bigip_monitor_tcp
|
||||
state: absent
|
||||
server: "{{ f5server }}"
|
||||
user: "{{ f5user }}"
|
||||
password: "{{ f5password }}"
|
||||
name: "{{ monitorname }}"
|
||||
with_flattened:
|
||||
- f5monitors-tcp
|
||||
- f5monitors-halftcp
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
import bigsuds
|
||||
except ImportError:
|
||||
bigsuds_found = False
|
||||
else:
|
||||
bigsuds_found = True
|
||||
|
||||
TEMPLATE_TYPE = DEFAULT_TEMPLATE_TYPE = 'TTYPE_TCP'
|
||||
TEMPLATE_TYPE_CHOICES = ['tcp', 'tcp_echo', 'tcp_half_open']
|
||||
DEFAULT_PARENT = DEFAULT_TEMPLATE_TYPE_CHOICE = DEFAULT_TEMPLATE_TYPE.replace('TTYPE_', '').lower()
|
||||
|
||||
|
||||
# ===========================================
|
||||
# bigip_monitor module generic methods.
|
||||
# these should be re-useable for other monitor types
|
||||
#
|
||||
|
||||
def bigip_api(bigip, user, password):
|
||||
|
||||
api = bigsuds.BIGIP(hostname=bigip, username=user, password=password)
|
||||
return api
|
||||
|
||||
|
||||
def check_monitor_exists(module, api, monitor, parent):
|
||||
|
||||
# hack to determine if monitor exists
|
||||
result = False
|
||||
try:
|
||||
ttype = api.LocalLB.Monitor.get_template_type(template_names=[monitor])[0]
|
||||
parent2 = api.LocalLB.Monitor.get_parent_template(template_names=[monitor])[0]
|
||||
if ttype == TEMPLATE_TYPE and parent == parent2:
|
||||
result = True
|
||||
else:
|
||||
module.fail_json(msg='Monitor already exists, but has a different type (%s) or parent(%s)' % (ttype, parent))
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
|
||||
def create_monitor(api, monitor, template_attributes):
|
||||
|
||||
try:
|
||||
api.LocalLB.Monitor.create_template(templates=[{'template_name': monitor, 'template_type': TEMPLATE_TYPE}], template_attributes=[template_attributes])
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "already exists" in str(e):
|
||||
return False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def delete_monitor(api, monitor):
|
||||
|
||||
try:
|
||||
api.LocalLB.Monitor.delete_template(template_names=[monitor])
|
||||
except bigsuds.OperationFailed, e:
|
||||
# maybe it was deleted since we checked
|
||||
if "was not found" in str(e):
|
||||
return False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def check_string_property(api, monitor, str_property):
|
||||
|
||||
try:
|
||||
return str_property == api.LocalLB.Monitor.get_template_string_property([monitor], [str_property['type']])[0]
|
||||
except bigsuds.OperationFailed, e:
|
||||
# happens in check mode if not created yet
|
||||
if "was not found" in str(e):
|
||||
return True
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def set_string_property(api, monitor, str_property):
|
||||
|
||||
api.LocalLB.Monitor.set_template_string_property(template_names=[monitor], values=[str_property])
|
||||
|
||||
|
||||
def check_integer_property(api, monitor, int_property):
|
||||
|
||||
try:
|
||||
return int_property == api.LocalLB.Monitor.get_template_integer_property([monitor], [int_property['type']])[0]
|
||||
except bigsuds.OperationFailed, e:
|
||||
# happens in check mode if not created yet
|
||||
if "was not found" in str(e):
|
||||
return True
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def set_integer_property(api, monitor, int_property):
|
||||
|
||||
api.LocalLB.Monitor.set_template_int_property(template_names=[monitor], values=[int_property])
|
||||
|
||||
|
||||
def update_monitor_properties(api, module, monitor, template_string_properties, template_integer_properties):
|
||||
|
||||
changed = False
|
||||
for str_property in template_string_properties:
|
||||
if str_property['value'] is not None and not check_string_property(api, monitor, str_property):
|
||||
if not module.check_mode:
|
||||
set_string_property(api, monitor, str_property)
|
||||
changed = True
|
||||
for int_property in template_integer_properties:
|
||||
if int_property['value'] is not None and not check_integer_property(api, monitor, int_property):
|
||||
if not module.check_mode:
|
||||
set_integer_property(api, monitor, int_property)
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
def get_ipport(api, monitor):
|
||||
|
||||
return api.LocalLB.Monitor.get_template_destination(template_names=[monitor])[0]
|
||||
|
||||
|
||||
def set_ipport(api, monitor, ipport):
|
||||
|
||||
try:
|
||||
api.LocalLB.Monitor.set_template_destination(template_names=[monitor], destinations=[ipport])
|
||||
return True, ""
|
||||
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "Cannot modify the address type of monitor" in str(e):
|
||||
return False, "Cannot modify the address type of monitor if already assigned to a pool."
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
|
||||
# ===========================================
|
||||
# main loop
|
||||
#
|
||||
# writing a module for other monitor types should
|
||||
# only need an updated main() (and monitor specific functions)
|
||||
|
||||
def main():
|
||||
|
||||
# begin monitor specific stuff
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
server = dict(required=True),
|
||||
user = dict(required=True),
|
||||
password = dict(required=True),
|
||||
partition = dict(default='Common'),
|
||||
state = dict(default='present', choices=['present', 'absent']),
|
||||
name = dict(required=True),
|
||||
type = dict(default=DEFAULT_TEMPLATE_TYPE_CHOICE, choices=TEMPLATE_TYPE_CHOICES),
|
||||
parent = dict(default=DEFAULT_PARENT),
|
||||
parent_partition = dict(default='Common'),
|
||||
send = dict(required=False),
|
||||
receive = dict(required=False),
|
||||
ip = dict(required=False),
|
||||
port = dict(required=False, type='int'),
|
||||
interval = dict(required=False, type='int'),
|
||||
timeout = dict(required=False, type='int'),
|
||||
time_until_up = dict(required=False, type='int', default=0)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
server = module.params['server']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
partition = module.params['partition']
|
||||
parent_partition = module.params['parent_partition']
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
type = 'TTYPE_' + module.params['type'].upper()
|
||||
parent = "/%s/%s" % (parent_partition, module.params['parent'])
|
||||
monitor = "/%s/%s" % (partition, name)
|
||||
send = module.params['send']
|
||||
receive = module.params['receive']
|
||||
ip = module.params['ip']
|
||||
port = module.params['port']
|
||||
interval = module.params['interval']
|
||||
timeout = module.params['timeout']
|
||||
time_until_up = module.params['time_until_up']
|
||||
|
||||
# tcp monitor has multiple types, so overrule
|
||||
global TEMPLATE_TYPE
|
||||
TEMPLATE_TYPE = type
|
||||
|
||||
# end monitor specific stuff
|
||||
|
||||
if not bigsuds_found:
|
||||
module.fail_json(msg="the python bigsuds module is required")
|
||||
api = bigip_api(server, user, password)
|
||||
monitor_exists = check_monitor_exists(module, api, monitor, parent)
|
||||
|
||||
|
||||
# ipport is a special setting
|
||||
if monitor_exists: # make sure to not update current settings if not asked
|
||||
cur_ipport = get_ipport(api, monitor)
|
||||
if ip is None:
|
||||
ip = cur_ipport['ipport']['address']
|
||||
if port is None:
|
||||
port = cur_ipport['ipport']['port']
|
||||
else: # use API defaults if not defined to create it
|
||||
if interval is None:
|
||||
interval = 5
|
||||
if timeout is None:
|
||||
timeout = 16
|
||||
if ip is None:
|
||||
ip = '0.0.0.0'
|
||||
if port is None:
|
||||
port = 0
|
||||
if send is None:
|
||||
send = ''
|
||||
if receive is None:
|
||||
receive = ''
|
||||
|
||||
# define and set address type
|
||||
if ip == '0.0.0.0' and port == 0:
|
||||
address_type = 'ATYPE_STAR_ADDRESS_STAR_PORT'
|
||||
elif ip == '0.0.0.0' and port != 0:
|
||||
address_type = 'ATYPE_STAR_ADDRESS_EXPLICIT_PORT'
|
||||
elif ip != '0.0.0.0' and port != 0:
|
||||
address_type = 'ATYPE_EXPLICIT_ADDRESS_EXPLICIT_PORT'
|
||||
else:
|
||||
address_type = 'ATYPE_UNSET'
|
||||
|
||||
ipport = {'address_type': address_type,
|
||||
'ipport': {'address': ip,
|
||||
'port': port}}
|
||||
|
||||
template_attributes = {'parent_template': parent,
|
||||
'interval': interval,
|
||||
'timeout': timeout,
|
||||
'dest_ipport': ipport,
|
||||
'is_read_only': False,
|
||||
'is_directly_usable': True}
|
||||
|
||||
# monitor specific stuff
|
||||
if type == 'TTYPE_TCP':
|
||||
template_string_properties = [{'type': 'STYPE_SEND',
|
||||
'value': send},
|
||||
{'type': 'STYPE_RECEIVE',
|
||||
'value': receive}]
|
||||
else:
|
||||
template_string_properties = []
|
||||
|
||||
template_integer_properties = [{'type': 'ITYPE_INTERVAL',
|
||||
'value': interval},
|
||||
{'type': 'ITYPE_TIMEOUT',
|
||||
'value': timeout},
|
||||
{'type': 'ITYPE_TIME_UNTIL_UP',
|
||||
'value': interval}]
|
||||
|
||||
# main logic, monitor generic
|
||||
|
||||
try:
|
||||
result = {'changed': False} # default
|
||||
|
||||
|
||||
if state == 'absent':
|
||||
if monitor_exists:
|
||||
if not module.check_mode:
|
||||
# possible race condition if same task
|
||||
# on other node deleted it first
|
||||
result['changed'] |= delete_monitor(api, monitor)
|
||||
else:
|
||||
result['changed'] |= True
|
||||
|
||||
else: # state present
|
||||
## check for monitor itself
|
||||
if not monitor_exists: # create it
|
||||
if not module.check_mode:
|
||||
# again, check changed status here b/c race conditions
|
||||
# if other task already created it
|
||||
result['changed'] |= create_monitor(api, monitor, template_attributes)
|
||||
else:
|
||||
result['changed'] |= True
|
||||
|
||||
## check for monitor parameters
|
||||
# whether it already existed, or was just created, now update
|
||||
# the update functions need to check for check mode but
|
||||
# cannot update settings if it doesn't exist which happens in check mode
|
||||
if monitor_exists and not module.check_mode:
|
||||
result['changed'] |= update_monitor_properties(api, module, monitor,
|
||||
template_string_properties,
|
||||
template_integer_properties)
|
||||
# else assume nothing changed
|
||||
|
||||
# we just have to update the ipport if monitor already exists and it's different
|
||||
if monitor_exists and cur_ipport != ipport:
|
||||
set_ipport(api, monitor, ipport)
|
||||
result['changed'] |= True
|
||||
#else: monitor doesn't exist (check mode) or ipport is already ok
|
||||
|
||||
|
||||
except Exception, e:
|
||||
module.fail_json(msg="received exception: %s" % e)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
294
lib/ansible/modules/extras/network/f5/bigip_node.py
Normal file
294
lib/ansible/modules/extras/network/f5/bigip_node.py
Normal file
@@ -0,0 +1,294 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Matt Hite <mhite@hotmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: bigip_node
|
||||
short_description: "Manages F5 BIG-IP LTM nodes"
|
||||
description:
|
||||
- "Manages F5 BIG-IP LTM nodes via iControl SOAP API"
|
||||
version_added: "1.4"
|
||||
author: Matt Hite
|
||||
notes:
|
||||
- "Requires BIG-IP software version >= 11"
|
||||
- "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
|
||||
- "Best run as a local_action in your playbook"
|
||||
requirements:
|
||||
- bigsuds
|
||||
options:
|
||||
server:
|
||||
description:
|
||||
- BIG-IP host
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
user:
|
||||
description:
|
||||
- BIG-IP username
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
password:
|
||||
description:
|
||||
- BIG-IP password
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- Pool member state
|
||||
required: true
|
||||
default: present
|
||||
choices: ['present', 'absent']
|
||||
aliases: []
|
||||
partition:
|
||||
description:
|
||||
- Partition
|
||||
required: false
|
||||
default: 'Common'
|
||||
choices: []
|
||||
aliases: []
|
||||
name:
|
||||
description:
|
||||
- "Node name"
|
||||
required: false
|
||||
default: null
|
||||
choices: []
|
||||
host:
|
||||
description:
|
||||
- "Node IP. Required when state=present and node does not exist. Error when state=absent."
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: ['address', 'ip']
|
||||
description:
|
||||
description:
|
||||
- "Node description."
|
||||
required: false
|
||||
default: null
|
||||
choices: []
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
## playbook task examples:
|
||||
|
||||
---
|
||||
# file bigip-test.yml
|
||||
# ...
|
||||
- hosts: bigip-test
|
||||
tasks:
|
||||
- name: Add node
|
||||
local_action: >
|
||||
bigip_node
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
partition=matthite
|
||||
host="{{ ansible_default_ipv4["address"] }}"
|
||||
name="{{ ansible_default_ipv4["address"] }}"
|
||||
|
||||
# Note that the BIG-IP automatically names the node using the
|
||||
# IP address specified in previous play's host parameter.
|
||||
# Future plays referencing this node no longer use the host
|
||||
# parameter but instead use the name parameter.
|
||||
# Alternatively, you could have specified a name with the
|
||||
# name parameter when state=present.
|
||||
|
||||
- name: Modify node description
|
||||
local_action: >
|
||||
bigip_node
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
partition=matthite
|
||||
name="{{ ansible_default_ipv4["address"] }}"
|
||||
description="Our best server yet"
|
||||
|
||||
- name: Delete node
|
||||
local_action: >
|
||||
bigip_node
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=absent
|
||||
partition=matthite
|
||||
name="{{ ansible_default_ipv4["address"] }}"
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
import bigsuds
|
||||
except ImportError:
|
||||
bigsuds_found = False
|
||||
else:
|
||||
bigsuds_found = True
|
||||
|
||||
# ==========================
|
||||
# bigip_node module specific
|
||||
#
|
||||
|
||||
def bigip_api(bigip, user, password):
|
||||
api = bigsuds.BIGIP(hostname=bigip, username=user, password=password)
|
||||
return api
|
||||
|
||||
def node_exists(api, address):
|
||||
# hack to determine if node exists
|
||||
result = False
|
||||
try:
|
||||
api.LocalLB.NodeAddressV2.get_object_status(nodes=[address])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def create_node_address(api, address, name):
|
||||
try:
|
||||
api.LocalLB.NodeAddressV2.create(nodes=[name], addresses=[address], limits=[0])
|
||||
result = True
|
||||
desc = ""
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "already exists" in str(e):
|
||||
result = False
|
||||
desc = "referenced name or IP already in use"
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return (result, desc)
|
||||
|
||||
def get_node_address(api, name):
|
||||
return api.LocalLB.NodeAddressV2.get_address(nodes=[name])[0]
|
||||
|
||||
def delete_node_address(api, address):
|
||||
try:
|
||||
api.LocalLB.NodeAddressV2.delete_node_address(nodes=[address])
|
||||
result = True
|
||||
desc = ""
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "is referenced by a member of pool" in str(e):
|
||||
result = False
|
||||
desc = "node referenced by pool"
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return (result, desc)
|
||||
|
||||
def set_node_description(api, name, description):
|
||||
api.LocalLB.NodeAddressV2.set_description(nodes=[name],
|
||||
descriptions=[description])
|
||||
|
||||
def get_node_description(api, name):
|
||||
return api.LocalLB.NodeAddressV2.get_description(nodes=[name])[0]
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
server = dict(type='str', required=True),
|
||||
user = dict(type='str', required=True),
|
||||
password = dict(type='str', required=True),
|
||||
state = dict(type='str', default='present', choices=['present', 'absent']),
|
||||
partition = dict(type='str', default='Common'),
|
||||
name = dict(type='str', required=True),
|
||||
host = dict(type='str', aliases=['address', 'ip']),
|
||||
description = dict(type='str')
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
if not bigsuds_found:
|
||||
module.fail_json(msg="the python bigsuds module is required")
|
||||
|
||||
server = module.params['server']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
state = module.params['state']
|
||||
partition = module.params['partition']
|
||||
host = module.params['host']
|
||||
name = module.params['name']
|
||||
address = "/%s/%s" % (partition, name)
|
||||
description = module.params['description']
|
||||
|
||||
if state == 'absent' and host is not None:
|
||||
module.fail_json(msg="host parameter invalid when state=absent")
|
||||
|
||||
try:
|
||||
api = bigip_api(server, user, password)
|
||||
result = {'changed': False} # default
|
||||
|
||||
if state == 'absent':
|
||||
if node_exists(api, address):
|
||||
if not module.check_mode:
|
||||
deleted, desc = delete_node_address(api, address)
|
||||
if not deleted:
|
||||
module.fail_json(msg="unable to delete: %s" % desc)
|
||||
else:
|
||||
result = {'changed': True}
|
||||
else:
|
||||
# check-mode return value
|
||||
result = {'changed': True}
|
||||
|
||||
elif state == 'present':
|
||||
if not node_exists(api, address):
|
||||
if host is None:
|
||||
module.fail_json(msg="host parameter required when " \
|
||||
"state=present and node does not exist")
|
||||
if not module.check_mode:
|
||||
created, desc = create_node_address(api, address=host, name=address)
|
||||
if not created:
|
||||
module.fail_json(msg="unable to create: %s" % desc)
|
||||
else:
|
||||
result = {'changed': True}
|
||||
if description is not None:
|
||||
set_node_description(api, address, description)
|
||||
result = {'changed': True}
|
||||
else:
|
||||
# check-mode return value
|
||||
result = {'changed': True}
|
||||
else:
|
||||
# node exists -- potentially modify attributes
|
||||
if host is not None:
|
||||
if get_node_address(api, address) != host:
|
||||
module.fail_json(msg="Changing the node address is " \
|
||||
"not supported by the API; " \
|
||||
"delete and recreate the node.")
|
||||
if description is not None:
|
||||
if get_node_description(api, address) != description:
|
||||
if not module.check_mode:
|
||||
set_node_description(api, address, description)
|
||||
result = {'changed': True}
|
||||
|
||||
except Exception, e:
|
||||
module.fail_json(msg="received exception: %s" % e)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
536
lib/ansible/modules/extras/network/f5/bigip_pool.py
Normal file
536
lib/ansible/modules/extras/network/f5/bigip_pool.py
Normal file
@@ -0,0 +1,536 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Matt Hite <mhite@hotmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: bigip_pool
|
||||
short_description: "Manages F5 BIG-IP LTM pools"
|
||||
description:
|
||||
- "Manages F5 BIG-IP LTM pools via iControl SOAP API"
|
||||
version_added: "1.2"
|
||||
author: Matt Hite
|
||||
notes:
|
||||
- "Requires BIG-IP software version >= 11"
|
||||
- "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
|
||||
- "Best run as a local_action in your playbook"
|
||||
requirements:
|
||||
- bigsuds
|
||||
options:
|
||||
server:
|
||||
description:
|
||||
- BIG-IP host
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
user:
|
||||
description:
|
||||
- BIG-IP username
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
password:
|
||||
description:
|
||||
- BIG-IP password
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- Pool/pool member state
|
||||
required: false
|
||||
default: present
|
||||
choices: ['present', 'absent']
|
||||
aliases: []
|
||||
name:
|
||||
description:
|
||||
- Pool name
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: ['pool']
|
||||
partition:
|
||||
description:
|
||||
- Partition of pool/pool member
|
||||
required: false
|
||||
default: 'Common'
|
||||
choices: []
|
||||
aliases: []
|
||||
lb_method:
|
||||
description:
|
||||
- Load balancing method
|
||||
version_added: "1.3"
|
||||
required: False
|
||||
default: 'round_robin'
|
||||
choices: ['round_robin', 'ratio_member', 'least_connection_member',
|
||||
'observed_member', 'predictive_member', 'ratio_node_address',
|
||||
'least_connection_node_address', 'fastest_node_address',
|
||||
'observed_node_address', 'predictive_node_address',
|
||||
'dynamic_ratio', 'fastest_app_response', 'least_sessions',
|
||||
'dynamic_ratio_member', 'l3_addr', 'unknown',
|
||||
'weighted_least_connection_member',
|
||||
'weighted_least_connection_node_address',
|
||||
'ratio_session', 'ratio_least_connection_member',
|
||||
'ratio_least_connection_node_address']
|
||||
aliases: []
|
||||
monitor_type:
|
||||
description:
|
||||
- Monitor rule type when monitors > 1
|
||||
version_added: "1.3"
|
||||
required: False
|
||||
default: null
|
||||
choices: ['and_list', 'm_of_n']
|
||||
aliases: []
|
||||
quorum:
|
||||
description:
|
||||
- Monitor quorum value when monitor_type is m_of_n
|
||||
version_added: "1.3"
|
||||
required: False
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
monitors:
|
||||
description:
|
||||
- Monitor template name list. Always use the full path to the monitor.
|
||||
version_added: "1.3"
|
||||
required: False
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
slow_ramp_time:
|
||||
description:
|
||||
- Sets the ramp-up time (in seconds) to gradually ramp up the load on newly added or freshly detected up pool members
|
||||
version_added: "1.3"
|
||||
required: False
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
service_down_action:
|
||||
description:
|
||||
- Sets the action to take when node goes down in pool
|
||||
version_added: "1.3"
|
||||
required: False
|
||||
default: null
|
||||
choices: ['none', 'reset', 'drop', 'reselect']
|
||||
aliases: []
|
||||
host:
|
||||
description:
|
||||
- "Pool member IP"
|
||||
required: False
|
||||
default: null
|
||||
choices: []
|
||||
aliases: ['address']
|
||||
port:
|
||||
description:
|
||||
- "Pool member port"
|
||||
required: False
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
## playbook task examples:
|
||||
|
||||
---
|
||||
# file bigip-test.yml
|
||||
# ...
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- name: Create pool
|
||||
local_action: >
|
||||
bigip_pool
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
name=matthite-pool
|
||||
partition=matthite
|
||||
lb_method=least_connection_member
|
||||
slow_ramp_time=120
|
||||
|
||||
- name: Modify load balancer method
|
||||
local_action: >
|
||||
bigip_pool
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
name=matthite-pool
|
||||
partition=matthite
|
||||
lb_method=round_robin
|
||||
|
||||
- hosts: bigip-test
|
||||
tasks:
|
||||
- name: Add pool member
|
||||
local_action: >
|
||||
bigip_pool
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
name=matthite-pool
|
||||
partition=matthite
|
||||
host="{{ ansible_default_ipv4["address"] }}"
|
||||
port=80
|
||||
|
||||
- name: Remove pool member from pool
|
||||
local_action: >
|
||||
bigip_pool
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=absent
|
||||
name=matthite-pool
|
||||
partition=matthite
|
||||
host="{{ ansible_default_ipv4["address"] }}"
|
||||
port=80
|
||||
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- name: Delete pool
|
||||
local_action: >
|
||||
bigip_pool
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=absent
|
||||
name=matthite-pool
|
||||
partition=matthite
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
import bigsuds
|
||||
except ImportError:
|
||||
bigsuds_found = False
|
||||
else:
|
||||
bigsuds_found = True
|
||||
|
||||
# ===========================================
|
||||
# bigip_pool module specific support methods.
|
||||
#
|
||||
|
||||
def bigip_api(bigip, user, password):
|
||||
api = bigsuds.BIGIP(hostname=bigip, username=user, password=password)
|
||||
return api
|
||||
|
||||
def pool_exists(api, pool):
|
||||
# hack to determine if pool exists
|
||||
result = False
|
||||
try:
|
||||
api.LocalLB.Pool.get_object_status(pool_names=[pool])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def create_pool(api, pool, lb_method):
|
||||
# create requires lb_method but we don't want to default
|
||||
# to a value on subsequent runs
|
||||
if not lb_method:
|
||||
lb_method = 'round_robin'
|
||||
lb_method = "LB_METHOD_%s" % lb_method.strip().upper()
|
||||
api.LocalLB.Pool.create_v2(pool_names=[pool], lb_methods=[lb_method],
|
||||
members=[[]])
|
||||
|
||||
def remove_pool(api, pool):
|
||||
api.LocalLB.Pool.delete_pool(pool_names=[pool])
|
||||
|
||||
def get_lb_method(api, pool):
|
||||
lb_method = api.LocalLB.Pool.get_lb_method(pool_names=[pool])[0]
|
||||
lb_method = lb_method.strip().replace('LB_METHOD_', '').lower()
|
||||
return lb_method
|
||||
|
||||
def set_lb_method(api, pool, lb_method):
|
||||
lb_method = "LB_METHOD_%s" % lb_method.strip().upper()
|
||||
api.LocalLB.Pool.set_lb_method(pool_names=[pool], lb_methods=[lb_method])
|
||||
|
||||
def get_monitors(api, pool):
|
||||
result = api.LocalLB.Pool.get_monitor_association(pool_names=[pool])[0]['monitor_rule']
|
||||
monitor_type = result['type'].split("MONITOR_RULE_TYPE_")[-1].lower()
|
||||
quorum = result['quorum']
|
||||
monitor_templates = result['monitor_templates']
|
||||
return (monitor_type, quorum, monitor_templates)
|
||||
|
||||
def set_monitors(api, pool, monitor_type, quorum, monitor_templates):
|
||||
monitor_type = "MONITOR_RULE_TYPE_%s" % monitor_type.strip().upper()
|
||||
monitor_rule = {'type': monitor_type, 'quorum': quorum, 'monitor_templates': monitor_templates}
|
||||
monitor_association = {'pool_name': pool, 'monitor_rule': monitor_rule}
|
||||
api.LocalLB.Pool.set_monitor_association(monitor_associations=[monitor_association])
|
||||
|
||||
def get_slow_ramp_time(api, pool):
|
||||
result = api.LocalLB.Pool.get_slow_ramp_time(pool_names=[pool])[0]
|
||||
return result
|
||||
|
||||
def set_slow_ramp_time(api, pool, seconds):
|
||||
api.LocalLB.Pool.set_slow_ramp_time(pool_names=[pool], values=[seconds])
|
||||
|
||||
def get_action_on_service_down(api, pool):
|
||||
result = api.LocalLB.Pool.get_action_on_service_down(pool_names=[pool])[0]
|
||||
result = result.split("SERVICE_DOWN_ACTION_")[-1].lower()
|
||||
return result
|
||||
|
||||
def set_action_on_service_down(api, pool, action):
|
||||
action = "SERVICE_DOWN_ACTION_%s" % action.strip().upper()
|
||||
api.LocalLB.Pool.set_action_on_service_down(pool_names=[pool], actions=[action])
|
||||
|
||||
def member_exists(api, pool, address, port):
|
||||
# hack to determine if member exists
|
||||
result = False
|
||||
try:
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.get_member_object_status(pool_names=[pool],
|
||||
members=[members])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def delete_node_address(api, address):
|
||||
result = False
|
||||
try:
|
||||
api.LocalLB.NodeAddressV2.delete_node_address(nodes=[address])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "is referenced by a member of pool" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def remove_pool_member(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.remove_member_v2(pool_names=[pool], members=[members])
|
||||
|
||||
def add_pool_member(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.add_member_v2(pool_names=[pool], members=[members])
|
||||
|
||||
def main():
|
||||
lb_method_choices = ['round_robin', 'ratio_member',
|
||||
'least_connection_member', 'observed_member',
|
||||
'predictive_member', 'ratio_node_address',
|
||||
'least_connection_node_address',
|
||||
'fastest_node_address', 'observed_node_address',
|
||||
'predictive_node_address', 'dynamic_ratio',
|
||||
'fastest_app_response', 'least_sessions',
|
||||
'dynamic_ratio_member', 'l3_addr', 'unknown',
|
||||
'weighted_least_connection_member',
|
||||
'weighted_least_connection_node_address',
|
||||
'ratio_session', 'ratio_least_connection_member',
|
||||
'ratio_least_connection_node_address']
|
||||
|
||||
monitor_type_choices = ['and_list', 'm_of_n']
|
||||
|
||||
service_down_choices = ['none', 'reset', 'drop', 'reselect']
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
server = dict(type='str', required=True),
|
||||
user = dict(type='str', required=True),
|
||||
password = dict(type='str', required=True),
|
||||
state = dict(type='str', default='present', choices=['present', 'absent']),
|
||||
name = dict(type='str', required=True, aliases=['pool']),
|
||||
partition = dict(type='str', default='Common'),
|
||||
lb_method = dict(type='str', choices=lb_method_choices),
|
||||
monitor_type = dict(type='str', choices=monitor_type_choices),
|
||||
quorum = dict(type='int'),
|
||||
monitors = dict(type='list'),
|
||||
slow_ramp_time = dict(type='int'),
|
||||
service_down_action = dict(type='str', choices=service_down_choices),
|
||||
host = dict(type='str', aliases=['address']),
|
||||
port = dict(type='int')
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
if not bigsuds_found:
|
||||
module.fail_json(msg="the python bigsuds module is required")
|
||||
|
||||
server = module.params['server']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
state = module.params['state']
|
||||
name = module.params['name']
|
||||
partition = module.params['partition']
|
||||
pool = "/%s/%s" % (partition, name)
|
||||
lb_method = module.params['lb_method']
|
||||
if lb_method:
|
||||
lb_method = lb_method.lower()
|
||||
monitor_type = module.params['monitor_type']
|
||||
if monitor_type:
|
||||
monitor_type = monitor_type.lower()
|
||||
quorum = module.params['quorum']
|
||||
monitors = module.params['monitors']
|
||||
if monitors:
|
||||
monitors = []
|
||||
for monitor in module.params['monitors']:
|
||||
if "/" not in monitor:
|
||||
monitors.append("/%s/%s" % (partition, monitor))
|
||||
else:
|
||||
monitors.append(monitor)
|
||||
slow_ramp_time = module.params['slow_ramp_time']
|
||||
service_down_action = module.params['service_down_action']
|
||||
if service_down_action:
|
||||
service_down_action = service_down_action.lower()
|
||||
host = module.params['host']
|
||||
address = "/%s/%s" % (partition, host)
|
||||
port = module.params['port']
|
||||
|
||||
# sanity check user supplied values
|
||||
|
||||
if (host and not port) or (port and not host):
|
||||
module.fail_json(msg="both host and port must be supplied")
|
||||
|
||||
if 1 > port > 65535:
|
||||
module.fail_json(msg="valid ports must be in range 1 - 65535")
|
||||
|
||||
if monitors:
|
||||
if len(monitors) == 1:
|
||||
# set default required values for single monitor
|
||||
quorum = 0
|
||||
monitor_type = 'single'
|
||||
elif len(monitors) > 1:
|
||||
if not monitor_type:
|
||||
module.fail_json(msg="monitor_type required for monitors > 1")
|
||||
if monitor_type == 'm_of_n' and not quorum:
|
||||
module.fail_json(msg="quorum value required for monitor_type m_of_n")
|
||||
if monitor_type != 'm_of_n':
|
||||
quorum = 0
|
||||
elif monitor_type:
|
||||
# no monitors specified but monitor_type exists
|
||||
module.fail_json(msg="monitor_type require monitors parameter")
|
||||
elif quorum is not None:
|
||||
# no monitors specified but quorum exists
|
||||
module.fail_json(msg="quorum requires monitors parameter")
|
||||
|
||||
try:
|
||||
api = bigip_api(server, user, password)
|
||||
result = {'changed': False} # default
|
||||
|
||||
if state == 'absent':
|
||||
if host and port and pool:
|
||||
# member removal takes precedent
|
||||
if pool_exists(api, pool) and member_exists(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
remove_pool_member(api, pool, address, port)
|
||||
deleted = delete_node_address(api, address)
|
||||
result = {'changed': True, 'deleted': deleted}
|
||||
else:
|
||||
result = {'changed': True}
|
||||
elif pool_exists(api, pool):
|
||||
# no host/port supplied, must be pool removal
|
||||
if not module.check_mode:
|
||||
# hack to handle concurrent runs of module
|
||||
# pool might be gone before we actually remove it
|
||||
try:
|
||||
remove_pool(api, pool)
|
||||
result = {'changed': True}
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = {'changed': False}
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
else:
|
||||
# check-mode return value
|
||||
result = {'changed': True}
|
||||
|
||||
elif state == 'present':
|
||||
update = False
|
||||
if not pool_exists(api, pool):
|
||||
# pool does not exist -- need to create it
|
||||
if not module.check_mode:
|
||||
# a bit of a hack to handle concurrent runs of this module.
|
||||
# even though we've checked the pool doesn't exist,
|
||||
# it may exist by the time we run create_pool().
|
||||
# this catches the exception and does something smart
|
||||
# about it!
|
||||
try:
|
||||
create_pool(api, pool, lb_method)
|
||||
result = {'changed': True}
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "already exists" in str(e):
|
||||
update = True
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
else:
|
||||
if monitors:
|
||||
set_monitors(api, pool, monitor_type, quorum, monitors)
|
||||
if slow_ramp_time:
|
||||
set_slow_ramp_time(api, pool, slow_ramp_time)
|
||||
if service_down_action:
|
||||
set_action_on_service_down(api, pool, service_down_action)
|
||||
if host and port:
|
||||
add_pool_member(api, pool, address, port)
|
||||
else:
|
||||
# check-mode return value
|
||||
result = {'changed': True}
|
||||
else:
|
||||
# pool exists -- potentially modify attributes
|
||||
update = True
|
||||
|
||||
if update:
|
||||
if lb_method and lb_method != get_lb_method(api, pool):
|
||||
if not module.check_mode:
|
||||
set_lb_method(api, pool, lb_method)
|
||||
result = {'changed': True}
|
||||
if monitors:
|
||||
t_monitor_type, t_quorum, t_monitor_templates = get_monitors(api, pool)
|
||||
if (t_monitor_type != monitor_type) or (t_quorum != quorum) or (set(t_monitor_templates) != set(monitors)):
|
||||
if not module.check_mode:
|
||||
set_monitors(api, pool, monitor_type, quorum, monitors)
|
||||
result = {'changed': True}
|
||||
if slow_ramp_time and slow_ramp_time != get_slow_ramp_time(api, pool):
|
||||
if not module.check_mode:
|
||||
set_slow_ramp_time(api, pool, slow_ramp_time)
|
||||
result = {'changed': True}
|
||||
if service_down_action and service_down_action != get_action_on_service_down(api, pool):
|
||||
if not module.check_mode:
|
||||
set_action_on_service_down(api, pool, service_down_action)
|
||||
result = {'changed': True}
|
||||
if (host and port) and not member_exists(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
add_pool_member(api, pool, address, port)
|
||||
result = {'changed': True}
|
||||
|
||||
except Exception, e:
|
||||
module.fail_json(msg="received exception: %s" % e)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
378
lib/ansible/modules/extras/network/f5/bigip_pool_member.py
Normal file
378
lib/ansible/modules/extras/network/f5/bigip_pool_member.py
Normal file
@@ -0,0 +1,378 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, Matt Hite <mhite@hotmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: bigip_pool_member
|
||||
short_description: "Manages F5 BIG-IP LTM pool members"
|
||||
description:
|
||||
- "Manages F5 BIG-IP LTM pool members via iControl SOAP API"
|
||||
version_added: "1.4"
|
||||
author: Matt Hite
|
||||
notes:
|
||||
- "Requires BIG-IP software version >= 11"
|
||||
- "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
|
||||
- "Best run as a local_action in your playbook"
|
||||
- "Supersedes bigip_pool for managing pool members"
|
||||
|
||||
requirements:
|
||||
- bigsuds
|
||||
options:
|
||||
server:
|
||||
description:
|
||||
- BIG-IP host
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
user:
|
||||
description:
|
||||
- BIG-IP username
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
password:
|
||||
description:
|
||||
- BIG-IP password
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- Pool member state
|
||||
required: true
|
||||
default: present
|
||||
choices: ['present', 'absent']
|
||||
aliases: []
|
||||
pool:
|
||||
description:
|
||||
- Pool name. This pool must exist.
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
partition:
|
||||
description:
|
||||
- Partition
|
||||
required: false
|
||||
default: 'Common'
|
||||
choices: []
|
||||
aliases: []
|
||||
host:
|
||||
description:
|
||||
- Pool member IP
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: ['address', 'name']
|
||||
port:
|
||||
description:
|
||||
- Pool member port
|
||||
required: true
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
connection_limit:
|
||||
description:
|
||||
- Pool member connection limit. Setting this to 0 disables the limit.
|
||||
required: false
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
description:
|
||||
description:
|
||||
- Pool member description
|
||||
required: false
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
rate_limit:
|
||||
description:
|
||||
- Pool member rate limit (connections-per-second). Setting this to 0 disables the limit.
|
||||
required: false
|
||||
default: null
|
||||
choices: []
|
||||
aliases: []
|
||||
ratio:
|
||||
description:
|
||||
- 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
|
||||
choices: []
|
||||
aliases: []
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
## playbook task examples:
|
||||
|
||||
---
|
||||
# file bigip-test.yml
|
||||
# ...
|
||||
- hosts: bigip-test
|
||||
tasks:
|
||||
- name: Add pool member
|
||||
local_action: >
|
||||
bigip_pool_member
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
pool=matthite-pool
|
||||
partition=matthite
|
||||
host="{{ ansible_default_ipv4["address"] }}"
|
||||
port=80
|
||||
description="web server"
|
||||
connection_limit=100
|
||||
rate_limit=50
|
||||
ratio=2
|
||||
|
||||
- name: Modify pool member ratio and description
|
||||
local_action: >
|
||||
bigip_pool_member
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=present
|
||||
pool=matthite-pool
|
||||
partition=matthite
|
||||
host="{{ ansible_default_ipv4["address"] }}"
|
||||
port=80
|
||||
ratio=1
|
||||
description="nginx server"
|
||||
|
||||
- name: Remove pool member from pool
|
||||
local_action: >
|
||||
bigip_pool_member
|
||||
server=lb.mydomain.com
|
||||
user=admin
|
||||
password=mysecret
|
||||
state=absent
|
||||
pool=matthite-pool
|
||||
partition=matthite
|
||||
host="{{ ansible_default_ipv4["address"] }}"
|
||||
port=80
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
import bigsuds
|
||||
except ImportError:
|
||||
bigsuds_found = False
|
||||
else:
|
||||
bigsuds_found = True
|
||||
|
||||
# ===========================================
|
||||
# bigip_pool_member module specific support methods.
|
||||
#
|
||||
|
||||
def bigip_api(bigip, user, password):
|
||||
api = bigsuds.BIGIP(hostname=bigip, username=user, password=password)
|
||||
return api
|
||||
|
||||
def pool_exists(api, pool):
|
||||
# hack to determine if pool exists
|
||||
result = False
|
||||
try:
|
||||
api.LocalLB.Pool.get_object_status(pool_names=[pool])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def member_exists(api, pool, address, port):
|
||||
# hack to determine if member exists
|
||||
result = False
|
||||
try:
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.get_member_object_status(pool_names=[pool],
|
||||
members=[members])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "was not found" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def delete_node_address(api, address):
|
||||
result = False
|
||||
try:
|
||||
api.LocalLB.NodeAddressV2.delete_node_address(nodes=[address])
|
||||
result = True
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "is referenced by a member of pool" in str(e):
|
||||
result = False
|
||||
else:
|
||||
# genuine exception
|
||||
raise
|
||||
return result
|
||||
|
||||
def remove_pool_member(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.remove_member_v2(pool_names=[pool], members=[members])
|
||||
|
||||
def add_pool_member(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.add_member_v2(pool_names=[pool], members=[members])
|
||||
|
||||
def get_connection_limit(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
result = api.LocalLB.Pool.get_member_connection_limit(pool_names=[pool], members=[members])[0][0]
|
||||
return result
|
||||
|
||||
def set_connection_limit(api, pool, address, port, limit):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.set_member_connection_limit(pool_names=[pool], members=[members], limits=[[limit]])
|
||||
|
||||
def get_description(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
result = api.LocalLB.Pool.get_member_description(pool_names=[pool], members=[members])[0][0]
|
||||
return result
|
||||
|
||||
def set_description(api, pool, address, port, description):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.set_member_description(pool_names=[pool], members=[members], descriptions=[[description]])
|
||||
|
||||
def get_rate_limit(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
result = api.LocalLB.Pool.get_member_rate_limit(pool_names=[pool], members=[members])[0][0]
|
||||
return result
|
||||
|
||||
def set_rate_limit(api, pool, address, port, limit):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.set_member_rate_limit(pool_names=[pool], members=[members], limits=[[limit]])
|
||||
|
||||
def get_ratio(api, pool, address, port):
|
||||
members = [{'address': address, 'port': port}]
|
||||
result = api.LocalLB.Pool.get_member_ratio(pool_names=[pool], members=[members])[0][0]
|
||||
return result
|
||||
|
||||
def set_ratio(api, pool, address, port, ratio):
|
||||
members = [{'address': address, 'port': port}]
|
||||
api.LocalLB.Pool.set_member_ratio(pool_names=[pool], members=[members], ratios=[[ratio]])
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
server = dict(type='str', required=True),
|
||||
user = dict(type='str', required=True),
|
||||
password = dict(type='str', required=True),
|
||||
state = dict(type='str', default='present', choices=['present', 'absent']),
|
||||
pool = dict(type='str', required=True),
|
||||
partition = dict(type='str', default='Common'),
|
||||
host = dict(type='str', required=True, aliases=['address', 'name']),
|
||||
port = dict(type='int', required=True),
|
||||
connection_limit = dict(type='int'),
|
||||
description = dict(type='str'),
|
||||
rate_limit = dict(type='int'),
|
||||
ratio = dict(type='int')
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
if not bigsuds_found:
|
||||
module.fail_json(msg="the python bigsuds module is required")
|
||||
|
||||
server = module.params['server']
|
||||
user = module.params['user']
|
||||
password = module.params['password']
|
||||
state = module.params['state']
|
||||
partition = module.params['partition']
|
||||
pool = "/%s/%s" % (partition, module.params['pool'])
|
||||
connection_limit = module.params['connection_limit']
|
||||
description = module.params['description']
|
||||
rate_limit = module.params['rate_limit']
|
||||
ratio = module.params['ratio']
|
||||
host = module.params['host']
|
||||
address = "/%s/%s" % (partition, host)
|
||||
port = module.params['port']
|
||||
|
||||
# sanity check user supplied values
|
||||
|
||||
if (host and not port) or (port and not host):
|
||||
module.fail_json(msg="both host and port must be supplied")
|
||||
|
||||
if 1 > port > 65535:
|
||||
module.fail_json(msg="valid ports must be in range 1 - 65535")
|
||||
|
||||
try:
|
||||
api = bigip_api(server, user, password)
|
||||
if not pool_exists(api, pool):
|
||||
module.fail_json(msg="pool %s does not exist" % pool)
|
||||
result = {'changed': False} # default
|
||||
|
||||
if state == 'absent':
|
||||
if member_exists(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
remove_pool_member(api, pool, address, port)
|
||||
deleted = delete_node_address(api, address)
|
||||
result = {'changed': True, 'deleted': deleted}
|
||||
else:
|
||||
result = {'changed': True}
|
||||
|
||||
elif state == 'present':
|
||||
if not member_exists(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
add_pool_member(api, pool, address, port)
|
||||
if connection_limit is not None:
|
||||
set_connection_limit(api, pool, address, port, connection_limit)
|
||||
if description is not None:
|
||||
set_description(api, pool, address, port, description)
|
||||
if rate_limit is not None:
|
||||
set_rate_limit(api, pool, address, port, rate_limit)
|
||||
if ratio is not None:
|
||||
set_ratio(api, pool, address, port, ratio)
|
||||
result = {'changed': True}
|
||||
else:
|
||||
# pool member exists -- potentially modify attributes
|
||||
if connection_limit is not None and connection_limit != get_connection_limit(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
set_connection_limit(api, pool, address, port, connection_limit)
|
||||
result = {'changed': True}
|
||||
if description is not None and description != get_description(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
set_description(api, pool, address, port, description)
|
||||
result = {'changed': True}
|
||||
if rate_limit is not None and rate_limit != get_rate_limit(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
set_rate_limit(api, pool, address, port, rate_limit)
|
||||
result = {'changed': True}
|
||||
if ratio is not None and ratio != get_ratio(api, pool, address, port):
|
||||
if not module.check_mode:
|
||||
set_ratio(api, pool, address, port, ratio)
|
||||
result = {'changed': True}
|
||||
|
||||
except Exception, e:
|
||||
module.fail_json(msg="received exception: %s" % e)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user