Skip to content
This repository has been archived by the owner on Oct 30, 2018. It is now read-only.

Module to manage F5 GTM virtual servers #555

Closed
wants to merge 7 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
241 changes: 241 additions & 0 deletions network/f5/bigip_gtm_virtual_server.py
@@ -0,0 +1,241 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (c) 2015, Michael Perzel
#
# 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_gtm_virtual_server
short_description: "Manages F5 BIG-IP GTM virtual servers"
description:
- "Manages F5 BIG-IP GTM virtual servers"
version_added: "2.2"
author: 'Michael Perzel'
notes:
- "Requires BIG-IP software version >= 11.4"
- "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
- "Best run as a local_action in your playbook"
- "Tested with manager and above account privilege level"

requirements:
- bigsuds
options:
server:
description:
- BIG-IP host
required: true
user:
description:
- BIG-IP username
required: true
password:
description:
- BIG-IP password
required: true
state:
description:
- Virtual server state
required: false
default: present
choices: ['present', 'absent','enabled','disabled']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

many modules uses present as default and it became a convention. would you mind using present as default and set required to false?

virtual_server_name:
description:
- Virtual server name
required: True
virtual_server_server:
description:
- Virtual server server
required: true
host:
description:
- Virtual server host
required: false
default: None
aliases: ['address']
port:
description:
- Virtual server port
required: false
default: None
'''

RETURN = '''
bigip_gtm_virtual_server:
description: Provides the ability to create, delete, enable, disable GTM virtual servers
returned: success
type: dictionary
'''

EXAMPLES = '''
- name: Enable virtual server
local_action: >
bigip_gtm_virtual_server
server=192.168.0.1
user=admin
password=mysecret
virtual_server_name=myname
virtual_server_server=myserver
state=enabled
'''

try:
import bigsuds
except ImportError:
bigsuds_found = False
else:
bigsuds_found = True

def bigip_api(server, user, password):
api = bigsuds.BIGIP(hostname=server, username=user, password=password)
return api

def server_exists(api, server):
# hack to determine if virtual server exists
result = False
try:
api.GlobalLB.Server.get_object_status([server])
result = True
except bigsuds.OperationFailed, e:
if "was not found" in str(e):
result = False
else:
# genuine exception
raise
return result

def virtual_server_exists(api, name, server):
# hack to determine if virtual server exists
result = False
try:
virtual_server_id = {'name': name, 'server': server}
api.GlobalLB.VirtualServerV2.get_object_status([virtual_server_id])
result = True
except bigsuds.OperationFailed, e:
if "was not found" in str(e):
result = False
else:
# genuine exception
raise
return result

def add_virtual_server(api, virtual_server_name, virtual_server_server, address, port):
addresses = {'address': address, 'port': port}
virtual_server_id = {'name': virtual_server_name, 'server': virtual_server_server}
api.GlobalLB.VirtualServerV2.create([virtual_server_id], [addresses])

def remove_virtual_server(api, virtual_server_name, virtual_server_server):
virtual_server_id = {'name': virtual_server_name, 'server': virtual_server_server}
api.GlobalLB.VirtualServerV2.delete_virtual_server([virtual_server_id])

def get_virtual_server_state(api, name, server):
virtual_server_id = {'name': name, 'server': server}
state = api.GlobalLB.VirtualServerV2.get_enabled_state([virtual_server_id])
state = state[0].split('STATE_')[1].lower()
return state

def set_virtual_server_state(api, name, server, state):
virtual_server_id = {'name': name, 'server': server}
state = "STATE_%s" % state.strip().upper()
api.GlobalLB.VirtualServerV2.set_enabled_state([virtual_server_id], [state])

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, no_log=True),
state = dict(type='str', default='present', choices=['present', 'absent', 'enabled', 'disabled']),
host = dict(type='str', default=None, aliases=['address']),
port = dict(type='int', default=None),
virtual_server_name = dict(type='str', required=True),
virtual_server_server = dict(type='str', required=True)
),
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']
virtual_server_name = module.params['virtual_server_name']
virtual_server_server = module.params['virtual_server_server']
state = module.params['state']
address = module.params['host']
port = module.params['port']

result = {'changed': False} # default

try:
api = bigip_api(server, user, password)

if state == 'absent':
if virtual_server_exists(api, virtual_server_name, virtual_server_server):
if not module.check_mode:
remove_virtual_server(api, virtual_server_name, virtual_server_server)
result = {'changed': True}
else:
# check-mode return value
result = {'changed': True}
elif state == 'present':
if virtual_server_name and virtual_server_server and address and port:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when address and/or port are not set?

if not virtual_server_exists(api, virtual_server_name, virtual_server_server):
if not module.check_mode:
if server_exists(api, virtual_server_server):
add_virtual_server(api, virtual_server_name, virtual_server_server, address, port)
result = {'changed': True}
else:
module.fail_json(msg="server does not exist")
else:
# check-mode return value
result = {'changed': True}
else:
# virtual server exists -- potentially modify attributes --future feature
result = {'changed': False}
else:
module.fail_json(msg="Address and port are required to create virtual server")
elif state == 'enabled':
if not virtual_server_exists(api, virtual_server_name, virtual_server_server):
module.fail_json(msg="virtual server does not exist")
if state != get_virtual_server_state(api, virtual_server_name, virtual_server_server):
if not module.check_mode:
set_virtual_server_state(api, virtual_server_name, virtual_server_server, state)
result = {'changed': True}
else:
result = {'changed': True}
elif state == 'disabled':
if not virtual_server_exists(api, virtual_server_name, virtual_server_server):
module.fail_json(msg="virtual server does not exist")
if state != get_virtual_server_state(api, virtual_server_name, virtual_server_server):
if not module.check_mode:
set_virtual_server_state(api, virtual_server_name, virtual_server_server, state)
result = {'changed': True}
else:
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 *

if __name__ == '__main__':
main()