New module to patch GSLB service object with just GSLB pool member an… (#34365)

* New module to patch GSLB service object with just GSLB pool member and settings

* Update copyright notice.
This commit is contained in:
Gaurav Rastogi 2018-01-03 10:55:21 -08:00 committed by John R Barker
parent e2928da0fd
commit 627295365d

View file

@ -0,0 +1,298 @@
#!/usr/bin/python
"""
# Created on Aug 12, 2016
#
# @author: Gaurav Rastogi (grastogi@avinetworks.com) GitHub ID: grastogi23
#
# module_check: supported
#
# Copyright: (c) 2016 Gaurav Rastogi, <grastogi@avinetworks.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
"""
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: avi_gslbservice_patch_member
author: Gaurav Rastogi (grastogi@avinetworks.com)
short_description: Avi API Module
description:
- This module can be used for calling any resources defined in Avi REST API. U(https://avinetworks.com/)
- This module is useful for invoking HTTP Patch methods and accessing resources that do not have an REST object associated with them.
version_added: 2.5
requirements: [ avisdk ]
options:
data:
description:
- HTTP body of GSLB Service Member in YAML or JSON format.
params:
description:
- Query parameters passed to the HTTP API.
name:
description:
- Name of the GSLB Service
required: true
state:
description:
- The state that should be applied to the member. Member is
- identified using field member.ip.addr.
default: present
choices: ["absent","present"]
extends_documentation_fragment:
- avi
'''
EXAMPLES = '''
- name: Patch GSLB Service to add a new member and group
avi_gslbservice_patch_member:
controller: "{{ controller }}"
username: "{{ username }}"
password: "{{ password }}"
name: gs-3
api_version: 17.2.1
data:
group:
name: newfoo
priority: 60
members:
- enabled: true
ip:
addr: 10.30.10.66
type: V4
ratio: 3
api_version: 16.4
- name: Patch GSLB Service to delete an existing member
avi_gslbservice_patch_member:
controller: "{{ controller }}"
username: "{{ username }}"
password: "{{ password }}"
name: gs-3
state: absent
api_version: 17.2.1
data:
group:
name: newfoo
members:
- enabled: true
ip:
addr: 10.30.10.68
type: V4
ratio: 3
- name: Update priority of GSLB Service Pool
avi_gslbservice_patch_member:
controller: ""
username: ""
password: ""
name: gs-3
state: present
api_version: 17.2.1
data:
group:
name: newfoo
priority: 42
'''
RETURN = '''
obj:
description: Avi REST resource
returned: success, changed
type: dict
'''
import json
import time
from ansible.module_utils.basic import AnsibleModule
from copy import deepcopy
HAS_AVI = True
try:
from avi.sdk.avi_api import ApiSession
from avi.sdk.utils.ansible_utils import (
avi_obj_cmp, cleanup_absent_fields, ansible_return,
AviCheckModeResponse, AviCredentials)
from ansible.module_utils.network.avi.avi import (
avi_common_argument_spec, HAS_AVI)
except ImportError:
HAS_AVI = False
def delete_member(module, check_mode, api, tenant, tenant_uuid,
existing_obj, data, api_version):
members = data.get('group', {}).get('members', [])
patched_member_ids = set([m['ip']['addr'] for m in members if 'fqdn' not in m])
patched_member_fqdns = set([m['fqdn'] for m in members if 'fqdn' in m])
changed = False
rsp = None
if existing_obj and (patched_member_ids or patched_member_fqdns):
groups = [group for group in existing_obj.get('groups', [])
if group['name'] == data['group']['name']]
if groups:
changed = any(
[(lambda g: g['ip']['addr'] in patched_member_ids)(m)
for m in groups[0].get('members', []) if 'fqdn' not in m])
changed = changed or any(
[(lambda g: g['fqdn'] in patched_member_fqdns)(m)
for m in groups[0].get('members', []) if 'fqdn' in m])
if check_mode or not changed:
return changed, rsp
# should not come here if not found
group = groups[0]
new_members = []
for m in group.get('members', []):
if 'fqdn' in m:
if m['fqdn'] not in patched_member_fqdns:
new_members.append(m)
elif 'ip' in m:
if m['ip']['addr'] not in patched_member_ids:
new_members.append(m)
group['members'] = new_members
if not group['members']:
# Delete this group from the existing objects if it is empty.
# Controller also does not allow empty group.
existing_obj['groups'] = [
grp for grp in existing_obj.get('groups', []) if
grp['name'] != data['group']['name']]
# remove the members that are part of the list
# update the object
# added api version for AVI api call.
rsp = api.put('gslbservice/%s' % existing_obj['uuid'], data=existing_obj,
tenant=tenant, tenant_uuid=tenant_uuid, api_version=api_version)
return changed, rsp
def add_member(module, check_mode, api, tenant, tenant_uuid,
existing_obj, data, name, api_version):
rsp = None
if not existing_obj:
# create the object
changed = True
if check_mode:
rsp = AviCheckModeResponse(obj=None)
else:
# creates group with single member
req = {'name': name,
'groups': [data['group']]
}
# added api version for AVI api call.
rsp = api.post('gslbservice', data=req, tenant=tenant,
tenant_uuid=tenant_uuid, api_version=api_version)
else:
# found GSLB object
req = deepcopy(existing_obj)
if 'groups' not in req:
req['groups'] = []
groups = [group for group in req['groups']
if group['name'] == data['group']['name']]
if not groups:
# did not find the group
req['groups'].append(data['group'])
else:
# just update the existing group with members
group = groups[0]
group_info_wo_members = deepcopy(data['group'])
group_info_wo_members.pop('members', None)
group.update(group_info_wo_members)
if 'members' not in group:
group['members'] = []
new_members = []
for patch_member in data['group'].get('members', []):
found = False
for m in group['members']:
if 'fqdn' in patch_member and m.get('fqdn', '') == patch_member['fqdn']:
found = True
break
elif m['ip']['addr'] == patch_member['ip']['addr']:
found = True
break
if not found:
new_members.append(patch_member)
else:
m.update(patch_member)
# add any new members
group['members'].extend(new_members)
cleanup_absent_fields(req)
changed = not avi_obj_cmp(req, existing_obj)
if changed and not check_mode:
obj_path = '%s/%s' % ('gslbservice', existing_obj['uuid'])
# added api version for AVI api call.
rsp = api.put(obj_path, data=req, tenant=tenant,
tenant_uuid=tenant_uuid, api_version=api_version)
return changed, rsp
def main():
argument_specs = dict(
params=dict(type='dict'),
data=dict(type='dict'),
name=dict(type='str', required=True),
state=dict(default='present',
choices=['absent', 'present'])
)
argument_specs.update(avi_common_argument_spec())
module = AnsibleModule(argument_spec=argument_specs)
if not HAS_AVI:
return module.fail_json(msg=(
'Avi python API SDK (avisdk) is not installed. '
'For more details visit https://github.com/avinetworks/sdk.'))
api_creds = AviCredentials()
api_creds.update_from_ansible_module(module)
api = ApiSession.get_session(
api_creds.controller, api_creds.username, password=api_creds.password,
timeout=api_creds.timeout, tenant=api_creds.tenant,
tenant_uuid=api_creds.tenant_uuid, token=api_creds.token,
port=api_creds.port)
tenant = api_creds.tenant
tenant_uuid = api_creds.tenant_uuid
params = module.params.get('params', None)
data = module.params.get('data', None)
gparams = deepcopy(params) if params else {}
gparams.update({'include_refs': '', 'include_name': ''})
name = module.params.get('name', '')
state = module.params['state']
# Get the api version from module.
api_version = api_creds.api_version
"""
state: present
1. Check if the GSLB service is present
2. If not then create the GSLB service with the member
3. Check if the group exists
4. if not then create the group with the member
5. Check if the member is present
if not then add the member
state: absent
1. check if GSLB service is present if not then exit
2. check if group is present. if not then exit
3. check if member is present. if present then remove it.
"""
obj_type = 'gslbservice'
# Added api version to call
existing_obj = api.get_object_by_name(
obj_type, name, tenant=tenant, tenant_uuid=tenant_uuid,
params={'include_refs': '', 'include_name': ''}, api_version=api_version)
check_mode = module.check_mode
if state == 'absent':
# Added api version to call
changed, rsp = delete_member(module, check_mode, api, tenant,
tenant_uuid, existing_obj, data, api_version)
else:
# Added api version to call
changed, rsp = add_member(module, check_mode, api, tenant, tenant_uuid,
existing_obj, data, name, api_version)
if check_mode or not changed:
return module.exit_json(changed=changed, obj=existing_obj)
return ansible_return(module, rsp, changed, req=data)
if __name__ == '__main__':
main()