mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add netscaler_gslb_vserver (#27640)
This commit is contained in:
parent
60b3f80c6c
commit
e2f907ae3e
18 changed files with 2256 additions and 0 deletions
946
lib/ansible/modules/network/netscaler/netscaler_gslb_vserver.py
Normal file
946
lib/ansible/modules/network/netscaler/netscaler_gslb_vserver.py
Normal file
|
@ -0,0 +1,946 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2017 Citrix Systems
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'metadata_version': '1.0'}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: netscaler_gslb_vserver
|
||||
short_description: Configure gslb vserver entities in Netscaler.
|
||||
description:
|
||||
- Configure gslb vserver entities in Netscaler.
|
||||
|
||||
version_added: "2.4.0"
|
||||
|
||||
author: George Nikolopoulos (@giorgos-nikolopoulos)
|
||||
|
||||
options:
|
||||
|
||||
name:
|
||||
description:
|
||||
- >-
|
||||
Name for the GSLB virtual server. Must begin with an ASCII alphanumeric or underscore C(_) character,
|
||||
and must contain only ASCII alphanumeric, underscore C(_), hash C(#), period C(.), space, colon C(:), at C(@),
|
||||
equals C(=), and hyphen C(-) characters. Can be changed after the virtual server is created.
|
||||
- "Minimum length = 1"
|
||||
|
||||
servicetype:
|
||||
choices:
|
||||
- 'HTTP'
|
||||
- 'FTP'
|
||||
- 'TCP'
|
||||
- 'UDP'
|
||||
- 'SSL'
|
||||
- 'SSL_BRIDGE'
|
||||
- 'SSL_TCP'
|
||||
- 'NNTP'
|
||||
- 'ANY'
|
||||
- 'SIP_UDP'
|
||||
- 'SIP_TCP'
|
||||
- 'SIP_SSL'
|
||||
- 'RADIUS'
|
||||
- 'RDP'
|
||||
- 'RTSP'
|
||||
- 'MYSQL'
|
||||
- 'MSSQL'
|
||||
- 'ORACLE'
|
||||
description:
|
||||
- "Protocol used by services bound to the virtual server."
|
||||
- >-
|
||||
|
||||
dnsrecordtype:
|
||||
choices:
|
||||
- 'A'
|
||||
- 'AAAA'
|
||||
- 'CNAME'
|
||||
- 'NAPTR'
|
||||
description:
|
||||
- "DNS record type to associate with the GSLB virtual server's domain name."
|
||||
- "Default value: A"
|
||||
- "Possible values = A, AAAA, CNAME, NAPTR"
|
||||
|
||||
lbmethod:
|
||||
choices:
|
||||
- 'ROUNDROBIN'
|
||||
- 'LEASTCONNECTION'
|
||||
- 'LEASTRESPONSETIME'
|
||||
- 'SOURCEIPHASH'
|
||||
- 'LEASTBANDWIDTH'
|
||||
- 'LEASTPACKETS'
|
||||
- 'STATICPROXIMITY'
|
||||
- 'RTT'
|
||||
- 'CUSTOMLOAD'
|
||||
description:
|
||||
- "Load balancing method for the GSLB virtual server."
|
||||
- "Default value: LEASTCONNECTION"
|
||||
- >-
|
||||
Possible values = ROUNDROBIN, LEASTCONNECTION, LEASTRESPONSETIME, SOURCEIPHASH, LEASTBANDWIDTH,
|
||||
LEASTPACKETS, STATICPROXIMITY, RTT, CUSTOMLOAD
|
||||
|
||||
backuplbmethod:
|
||||
choices:
|
||||
- 'ROUNDROBIN'
|
||||
- 'LEASTCONNECTION'
|
||||
- 'LEASTRESPONSETIME'
|
||||
- 'SOURCEIPHASH'
|
||||
- 'LEASTBANDWIDTH'
|
||||
- 'LEASTPACKETS'
|
||||
- 'STATICPROXIMITY'
|
||||
- 'RTT'
|
||||
- 'CUSTOMLOAD'
|
||||
description:
|
||||
- >-
|
||||
Backup load balancing method. Becomes operational if the primary load balancing method fails or
|
||||
cannot be used. Valid only if the primary method is based on either round-trip time (RTT) or static
|
||||
proximity.
|
||||
|
||||
netmask:
|
||||
description:
|
||||
- "IPv4 network mask for use in the SOURCEIPHASH load balancing method."
|
||||
- "Minimum length = 1"
|
||||
|
||||
v6netmasklen:
|
||||
description:
|
||||
- >-
|
||||
Number of bits to consider, in an IPv6 source IP address, for creating the hash that is required by
|
||||
the C(SOURCEIPHASH) load balancing method.
|
||||
- "Default value: C(128)"
|
||||
- "Minimum value = C(1)"
|
||||
- "Maximum value = C(128)"
|
||||
|
||||
tolerance:
|
||||
description:
|
||||
- >-
|
||||
Site selection tolerance, in milliseconds, for implementing the RTT load balancing method. If a
|
||||
site's RTT deviates from the lowest RTT by more than the specified tolerance, the site is not
|
||||
considered when the NetScaler appliance makes a GSLB decision. The appliance implements the round
|
||||
robin method of global server load balancing between sites whose RTT values are within the specified
|
||||
tolerance. If the tolerance is 0 (zero), the appliance always sends clients the IP address of the
|
||||
site with the lowest RTT.
|
||||
- "Minimum value = C(0)"
|
||||
- "Maximum value = C(100)"
|
||||
|
||||
persistencetype:
|
||||
choices:
|
||||
- 'SOURCEIP'
|
||||
- 'NONE'
|
||||
description:
|
||||
- "Use source IP address based persistence for the virtual server."
|
||||
- >-
|
||||
After the load balancing method selects a service for the first packet, the IP address received in
|
||||
response to the DNS query is used for subsequent requests from the same client.
|
||||
|
||||
persistenceid:
|
||||
description:
|
||||
- >-
|
||||
The persistence ID for the GSLB virtual server. The ID is a positive integer that enables GSLB sites
|
||||
to identify the GSLB virtual server, and is required if source IP address based or spill over based
|
||||
persistence is enabled on the virtual server.
|
||||
- "Minimum value = C(0)"
|
||||
- "Maximum value = C(65535)"
|
||||
|
||||
persistmask:
|
||||
description:
|
||||
- >-
|
||||
The optional IPv4 network mask applied to IPv4 addresses to establish source IP address based
|
||||
persistence.
|
||||
- "Minimum length = 1"
|
||||
|
||||
v6persistmasklen:
|
||||
description:
|
||||
- >-
|
||||
Number of bits to consider in an IPv6 source IP address when creating source IP address based
|
||||
persistence sessions.
|
||||
- "Default value: C(128)"
|
||||
- "Minimum value = C(1)"
|
||||
- "Maximum value = C(128)"
|
||||
|
||||
timeout:
|
||||
description:
|
||||
- "Idle time, in minutes, after which a persistence entry is cleared."
|
||||
- "Default value: C(2)"
|
||||
- "Minimum value = C(2)"
|
||||
- "Maximum value = C(1440)"
|
||||
|
||||
mir:
|
||||
choices:
|
||||
- 'ENABLED'
|
||||
- 'DISABLED'
|
||||
description:
|
||||
- "Include multiple IP addresses in the DNS responses sent to clients."
|
||||
|
||||
disableprimaryondown:
|
||||
choices:
|
||||
- 'ENABLED'
|
||||
- 'DISABLED'
|
||||
description:
|
||||
- >-
|
||||
Continue to direct traffic to the backup chain even after the primary GSLB virtual server returns to
|
||||
the UP state. Used when spillover is configured for the virtual server.
|
||||
|
||||
dynamicweight:
|
||||
choices:
|
||||
- 'SERVICECOUNT'
|
||||
- 'SERVICEWEIGHT'
|
||||
- 'DISABLED'
|
||||
description:
|
||||
- >-
|
||||
Specify if the appliance should consider the service count, service weights, or ignore both when
|
||||
using weight-based load balancing methods. The state of the number of services bound to the virtual
|
||||
server help the appliance to select the service.
|
||||
|
||||
considereffectivestate:
|
||||
choices:
|
||||
- 'NONE'
|
||||
- 'STATE_ONLY'
|
||||
description:
|
||||
- >-
|
||||
If the primary state of all bound GSLB services is DOWN, consider the effective states of all the
|
||||
GSLB services, obtained through the Metrics Exchange Protocol (MEP), when determining the state of
|
||||
the GSLB virtual server. To consider the effective state, set the parameter to STATE_ONLY. To
|
||||
disregard the effective state, set the parameter to NONE.
|
||||
- >-
|
||||
The effective state of a GSLB service is the ability of the corresponding virtual server to serve
|
||||
traffic. The effective state of the load balancing virtual server, which is transferred to the GSLB
|
||||
service, is UP even if only one virtual server in the backup chain of virtual servers is in the UP
|
||||
state.
|
||||
|
||||
comment:
|
||||
description:
|
||||
- "Any comments that you might want to associate with the GSLB virtual server."
|
||||
|
||||
somethod:
|
||||
choices:
|
||||
- 'CONNECTION'
|
||||
- 'DYNAMICCONNECTION'
|
||||
- 'BANDWIDTH'
|
||||
- 'HEALTH'
|
||||
- 'NONE'
|
||||
description:
|
||||
- "Type of threshold that, when exceeded, triggers spillover. Available settings function as follows:"
|
||||
- "* C(CONNECTION) - Spillover occurs when the number of client connections exceeds the threshold."
|
||||
- >-
|
||||
* C(DYNAMICCONNECTION) - Spillover occurs when the number of client connections at the GSLB virtual
|
||||
server exceeds the sum of the maximum client (Max Clients) settings for bound GSLB services. Do not
|
||||
specify a spillover threshold for this setting, because the threshold is implied by the Max Clients
|
||||
settings of the bound GSLB services.
|
||||
- >-
|
||||
* C(BANDWIDTH) - Spillover occurs when the bandwidth consumed by the GSLB virtual server's incoming and
|
||||
outgoing traffic exceeds the threshold.
|
||||
- >-
|
||||
* C(HEALTH) - Spillover occurs when the percentage of weights of the GSLB services that are UP drops
|
||||
below the threshold. For example, if services gslbSvc1, gslbSvc2, and gslbSvc3 are bound to a virtual
|
||||
server, with weights 1, 2, and 3, and the spillover threshold is 50%, spillover occurs if gslbSvc1
|
||||
and gslbSvc3 or gslbSvc2 and gslbSvc3 transition to DOWN.
|
||||
- "* C(NONE) - Spillover does not occur."
|
||||
|
||||
sopersistence:
|
||||
choices:
|
||||
- 'ENABLED'
|
||||
- 'DISABLED'
|
||||
description:
|
||||
- >-
|
||||
If spillover occurs, maintain source IP address based persistence for both primary and backup GSLB
|
||||
virtual servers.
|
||||
|
||||
sopersistencetimeout:
|
||||
description:
|
||||
- "Timeout for spillover persistence, in minutes."
|
||||
- "Default value: C(2)"
|
||||
- "Minimum value = C(2)"
|
||||
- "Maximum value = C(1440)"
|
||||
|
||||
sothreshold:
|
||||
description:
|
||||
- >-
|
||||
Threshold at which spillover occurs. Specify an integer for the CONNECTION spillover method, a
|
||||
bandwidth value in kilobits per second for the BANDWIDTH method (do not enter the units), or a
|
||||
percentage for the HEALTH method (do not enter the percentage symbol).
|
||||
- "Minimum value = C(1)"
|
||||
- "Maximum value = C(4294967287)"
|
||||
|
||||
sobackupaction:
|
||||
choices:
|
||||
- 'DROP'
|
||||
- 'ACCEPT'
|
||||
- 'REDIRECT'
|
||||
description:
|
||||
- >-
|
||||
Action to be performed if spillover is to take effect, but no backup chain to spillover is usable or
|
||||
exists.
|
||||
|
||||
appflowlog:
|
||||
choices:
|
||||
- 'ENABLED'
|
||||
- 'DISABLED'
|
||||
description:
|
||||
- "Enable logging appflow flow information."
|
||||
|
||||
domain_bindings:
|
||||
description:
|
||||
- >-
|
||||
List of bindings for domains for this glsb vserver.
|
||||
suboptions:
|
||||
cookietimeout:
|
||||
description:
|
||||
- Timeout, in minutes, for the GSLB site cookie.
|
||||
|
||||
domainname:
|
||||
description:
|
||||
- Domain name for which to change the time to live (TTL) and/or backup service IP address.
|
||||
|
||||
ttl:
|
||||
description:
|
||||
- Time to live (TTL) for the domain.
|
||||
|
||||
sitedomainttl:
|
||||
description:
|
||||
- >-
|
||||
TTL, in seconds, for all internally created site domains (created when a site prefix is
|
||||
configured on a GSLB service) that are associated with this virtual server.
|
||||
- Minimum value = C(1)
|
||||
|
||||
service_bindings:
|
||||
description:
|
||||
- List of bindings for gslb services bound to this gslb virtual server.
|
||||
suboptions:
|
||||
servicename:
|
||||
description:
|
||||
- Name of the GSLB service for which to change the weight.
|
||||
weight:
|
||||
description:
|
||||
- Weight to assign to the GSLB service.
|
||||
|
||||
disabled:
|
||||
description:
|
||||
- When set to C(yes) the GSLB Vserver state will be set to DISABLED.
|
||||
- When set to C(no) the GSLB Vserver state will be set to ENABLED.
|
||||
- >-
|
||||
Note that due to limitations of the underlying NITRO API a C(disabled) state change alone
|
||||
does not cause the module result to report a changed status.
|
||||
type: bool
|
||||
default: false
|
||||
|
||||
|
||||
|
||||
|
||||
extends_documentation_fragment: netscaler
|
||||
requirements:
|
||||
- nitro python sdk
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
'''
|
||||
|
||||
|
||||
import copy
|
||||
|
||||
try:
|
||||
from nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver import gslbvserver
|
||||
from nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_gslbservice_binding import gslbvserver_gslbservice_binding
|
||||
from nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_domain_binding import gslbvserver_domain_binding
|
||||
from nssrc.com.citrix.netscaler.nitro.exception.nitro_exception import nitro_exception
|
||||
PYTHON_SDK_IMPORTED = True
|
||||
except ImportError as e:
|
||||
PYTHON_SDK_IMPORTED = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.netscaler import (
|
||||
ConfigProxy,
|
||||
get_nitro_client,
|
||||
netscaler_common_arguments,
|
||||
log,
|
||||
loglines,
|
||||
ensure_feature_is_enabled,
|
||||
get_immutables_intersection,
|
||||
complete_missing_attributes
|
||||
)
|
||||
|
||||
|
||||
gslbvserver_domain_binding_rw_attrs = [
|
||||
'name',
|
||||
'domainname',
|
||||
'backupipflag',
|
||||
'cookietimeout',
|
||||
'backupip',
|
||||
'ttl',
|
||||
'sitedomainttl',
|
||||
'cookie_domainflag',
|
||||
]
|
||||
|
||||
gslbvserver_gslbservice_binding_rw_attrs = [
|
||||
'name',
|
||||
'servicename',
|
||||
'weight',
|
||||
]
|
||||
|
||||
|
||||
def get_actual_domain_bindings(client, module):
|
||||
log('get_actual_domain_bindings')
|
||||
# Get actual domain bindings and index them by domainname
|
||||
actual_domain_bindings = {}
|
||||
if gslbvserver_domain_binding.count(client, name=module.params['name']) != 0:
|
||||
# Get all domain bindings associated with the named gslb vserver
|
||||
fetched_domain_bindings = gslbvserver_domain_binding.get(client, name=module.params['name'])
|
||||
# index by domainname
|
||||
for binding in fetched_domain_bindings:
|
||||
complete_missing_attributes(binding, gslbvserver_domain_binding_rw_attrs, fill_value=None)
|
||||
actual_domain_bindings[binding.domainname] = binding
|
||||
return actual_domain_bindings
|
||||
|
||||
|
||||
def get_configured_domain_bindings_proxys(client, module):
|
||||
log('get_configured_domain_bindings_proxys')
|
||||
configured_domain_proxys = {}
|
||||
# Get configured domain bindings and index them by domainname
|
||||
if module.params['domain_bindings'] is not None:
|
||||
for configured_domain_binding in module.params['domain_bindings']:
|
||||
binding_values = copy.deepcopy(configured_domain_binding)
|
||||
binding_values['name'] = module.params['name']
|
||||
gslbvserver_domain_binding_proxy = ConfigProxy(
|
||||
actual=gslbvserver_domain_binding(),
|
||||
client=client,
|
||||
attribute_values_dict=binding_values,
|
||||
readwrite_attrs=gslbvserver_domain_binding_rw_attrs,
|
||||
readonly_attrs=[],
|
||||
)
|
||||
configured_domain_proxys[configured_domain_binding['domainname']] = gslbvserver_domain_binding_proxy
|
||||
return configured_domain_proxys
|
||||
|
||||
|
||||
def sync_domain_bindings(client, module):
|
||||
log('sync_domain_bindings')
|
||||
|
||||
actual_domain_bindings = get_actual_domain_bindings(client, module)
|
||||
configured_domain_proxys = get_configured_domain_bindings_proxys(client, module)
|
||||
|
||||
# Delete actual bindings not in configured bindings
|
||||
for domainname, actual_domain_binding in actual_domain_bindings.items():
|
||||
if domainname not in configured_domain_proxys.keys():
|
||||
log('Deleting absent binding for domain %s' % domainname)
|
||||
gslbvserver_domain_binding.delete(client, actual_domain_binding)
|
||||
|
||||
# Delete actual bindings that differ from configured
|
||||
for proxy_key, binding_proxy in configured_domain_proxys.items():
|
||||
if proxy_key in actual_domain_bindings:
|
||||
actual_binding = actual_domain_bindings[proxy_key]
|
||||
if not binding_proxy.has_equal_attributes(actual_binding):
|
||||
log('Deleting differing binding for domain %s' % binding_proxy.domainname)
|
||||
gslbvserver_domain_binding.delete(client, actual_binding)
|
||||
log('Adding anew binding for domain %s' % binding_proxy.domainname)
|
||||
binding_proxy.add()
|
||||
|
||||
# Add configured domains that are missing from actual
|
||||
for proxy_key, binding_proxy in configured_domain_proxys.items():
|
||||
if proxy_key not in actual_domain_bindings.keys():
|
||||
log('Adding domain binding for domain %s' % binding_proxy.domainname)
|
||||
binding_proxy.add()
|
||||
|
||||
|
||||
def domain_bindings_identical(client, module):
|
||||
log('domain_bindings_identical')
|
||||
actual_domain_bindings = get_actual_domain_bindings(client, module)
|
||||
configured_domain_proxys = get_configured_domain_bindings_proxys(client, module)
|
||||
|
||||
actual_keyset = set(actual_domain_bindings.keys())
|
||||
configured_keyset = set(configured_domain_proxys.keys())
|
||||
|
||||
symmetric_difference = actual_keyset ^ configured_keyset
|
||||
|
||||
log('symmetric difference %s' % symmetric_difference)
|
||||
if len(symmetric_difference) != 0:
|
||||
return False
|
||||
|
||||
# Item for item equality test
|
||||
for key, proxy in configured_domain_proxys.items():
|
||||
diff = proxy.diff_object(actual_domain_bindings[key])
|
||||
if 'backupipflag' in diff:
|
||||
del diff['backupipflag']
|
||||
if not len(diff) == 0:
|
||||
return False
|
||||
# Fallthrough to True result
|
||||
return True
|
||||
|
||||
|
||||
def get_actual_service_bindings(client, module):
|
||||
log('get_actual_service_bindings')
|
||||
# Get actual domain bindings and index them by domainname
|
||||
actual_bindings = {}
|
||||
if gslbvserver_gslbservice_binding.count(client, name=module.params['name']) != 0:
|
||||
# Get all service bindings associated with the named gslb vserver
|
||||
fetched_bindings = gslbvserver_gslbservice_binding.get(client, name=module.params['name'])
|
||||
# index by servicename
|
||||
for binding in fetched_bindings:
|
||||
complete_missing_attributes(binding, gslbvserver_gslbservice_binding_rw_attrs, fill_value=None)
|
||||
actual_bindings[binding.servicename] = binding
|
||||
|
||||
return actual_bindings
|
||||
|
||||
|
||||
def get_configured_service_bindings(client, module):
|
||||
log('get_configured_service_bindings_proxys')
|
||||
configured_proxys = {}
|
||||
# Get configured domain bindings and index them by domainname
|
||||
if module.params['service_bindings'] is not None:
|
||||
for configured_binding in module.params['service_bindings']:
|
||||
binding_values = copy.deepcopy(configured_binding)
|
||||
binding_values['name'] = module.params['name']
|
||||
gslbvserver_service_binding_proxy = ConfigProxy(
|
||||
actual=gslbvserver_gslbservice_binding(),
|
||||
client=client,
|
||||
attribute_values_dict=binding_values,
|
||||
readwrite_attrs=gslbvserver_gslbservice_binding_rw_attrs,
|
||||
readonly_attrs=[],
|
||||
)
|
||||
configured_proxys[configured_binding['servicename']] = gslbvserver_service_binding_proxy
|
||||
return configured_proxys
|
||||
|
||||
|
||||
def sync_service_bindings(client, module):
|
||||
actual = get_actual_service_bindings(client, module)
|
||||
configured = get_configured_service_bindings(client, module)
|
||||
|
||||
# Delete extraneous
|
||||
extraneous_service_bindings = list(set(actual.keys()) - set(configured.keys()))
|
||||
for servicename in extraneous_service_bindings:
|
||||
log('Deleting missing binding from service %s' % servicename)
|
||||
binding = actual[servicename]
|
||||
binding.name = module.params['name']
|
||||
gslbvserver_gslbservice_binding.delete(client, binding)
|
||||
|
||||
# Recreate different
|
||||
common_service_bindings = list(set(actual.keys()) & set(configured.keys()))
|
||||
for servicename in common_service_bindings:
|
||||
proxy = configured[servicename]
|
||||
binding = actual[servicename]
|
||||
if not proxy.has_equal_attributes(actual):
|
||||
log('Recreating differing service binding %s' % servicename)
|
||||
gslbvserver_gslbservice_binding.delete(client, binding)
|
||||
proxy.add()
|
||||
|
||||
# Add missing
|
||||
missing_service_bindings = list(set(configured.keys()) - set(actual.keys()))
|
||||
for servicename in missing_service_bindings:
|
||||
proxy = configured[servicename]
|
||||
log('Adding missing service binding %s' % servicename)
|
||||
proxy.add()
|
||||
|
||||
|
||||
def service_bindings_identical(client, module):
|
||||
actual_bindings = get_actual_service_bindings(client, module)
|
||||
configured_proxys = get_configured_service_bindings(client, module)
|
||||
|
||||
actual_keyset = set(actual_bindings.keys())
|
||||
configured_keyset = set(configured_proxys.keys())
|
||||
|
||||
symmetric_difference = actual_keyset ^ configured_keyset
|
||||
if len(symmetric_difference) != 0:
|
||||
return False
|
||||
|
||||
# Item for item equality test
|
||||
for key, proxy in configured_proxys.items():
|
||||
if key in actual_bindings.keys():
|
||||
if not proxy.has_equal_attributes(actual_bindings[key]):
|
||||
return False
|
||||
|
||||
# Fallthrough to True result
|
||||
return True
|
||||
|
||||
|
||||
def gslb_vserver_exists(client, module):
|
||||
if gslbvserver.count_filtered(client, 'name:%s' % module.params['name']) > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def gslb_vserver_identical(client, module, gslb_vserver_proxy):
|
||||
gslb_vserver_list = gslbvserver.get_filtered(client, 'name:%s' % module.params['name'])
|
||||
diff_dict = gslb_vserver_proxy.diff_object(gslb_vserver_list[0])
|
||||
if len(diff_dict) != 0:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def all_identical(client, module, gslb_vserver_proxy):
|
||||
return (
|
||||
gslb_vserver_identical(client, module, gslb_vserver_proxy) and
|
||||
domain_bindings_identical(client, module) and
|
||||
service_bindings_identical(client, module)
|
||||
)
|
||||
|
||||
|
||||
def diff_list(client, module, gslb_vserver_proxy):
|
||||
gslb_vserver_list = gslbvserver.get_filtered(client, 'name:%s' % module.params['name'])
|
||||
return gslb_vserver_proxy.diff_object(gslb_vserver_list[0])
|
||||
|
||||
|
||||
def do_state_change(client, module, gslb_vserver_proxy):
|
||||
if module.params['disabled']:
|
||||
log('Disabling glsb_vserver')
|
||||
result = gslbvserver.disable(client, gslb_vserver_proxy.actual)
|
||||
else:
|
||||
log('Enabling gslbvserver')
|
||||
result = gslbvserver.enable(client, gslb_vserver_proxy.actual)
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
module_specific_arguments = dict(
|
||||
name=dict(type='str'),
|
||||
servicetype=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'HTTP',
|
||||
'FTP',
|
||||
'TCP',
|
||||
'UDP',
|
||||
'SSL',
|
||||
'SSL_BRIDGE',
|
||||
'SSL_TCP',
|
||||
'NNTP',
|
||||
'ANY',
|
||||
'SIP_UDP',
|
||||
'SIP_TCP',
|
||||
'SIP_SSL',
|
||||
'RADIUS',
|
||||
'RDP',
|
||||
'RTSP',
|
||||
'MYSQL',
|
||||
'MSSQL',
|
||||
'ORACLE',
|
||||
]
|
||||
),
|
||||
dnsrecordtype=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'A',
|
||||
'AAAA',
|
||||
'CNAME',
|
||||
'NAPTR',
|
||||
]
|
||||
),
|
||||
lbmethod=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'ROUNDROBIN',
|
||||
'LEASTCONNECTION',
|
||||
'LEASTRESPONSETIME',
|
||||
'SOURCEIPHASH',
|
||||
'LEASTBANDWIDTH',
|
||||
'LEASTPACKETS',
|
||||
'STATICPROXIMITY',
|
||||
'RTT',
|
||||
'CUSTOMLOAD',
|
||||
]
|
||||
),
|
||||
backuplbmethod=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'ROUNDROBIN',
|
||||
'LEASTCONNECTION',
|
||||
'LEASTRESPONSETIME',
|
||||
'SOURCEIPHASH',
|
||||
'LEASTBANDWIDTH',
|
||||
'LEASTPACKETS',
|
||||
'STATICPROXIMITY',
|
||||
'RTT',
|
||||
'CUSTOMLOAD',
|
||||
]
|
||||
),
|
||||
netmask=dict(type='str'),
|
||||
v6netmasklen=dict(type='float'),
|
||||
tolerance=dict(type='float'),
|
||||
persistencetype=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'SOURCEIP',
|
||||
'NONE',
|
||||
]
|
||||
),
|
||||
persistenceid=dict(type='float'),
|
||||
persistmask=dict(type='str'),
|
||||
v6persistmasklen=dict(type='float'),
|
||||
timeout=dict(type='float'),
|
||||
mir=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'ENABLED',
|
||||
'DISABLED',
|
||||
]
|
||||
),
|
||||
disableprimaryondown=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'ENABLED',
|
||||
'DISABLED',
|
||||
]
|
||||
),
|
||||
dynamicweight=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'SERVICECOUNT',
|
||||
'SERVICEWEIGHT',
|
||||
'DISABLED',
|
||||
]
|
||||
),
|
||||
considereffectivestate=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'NONE',
|
||||
'STATE_ONLY',
|
||||
]
|
||||
),
|
||||
comment=dict(type='str'),
|
||||
somethod=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'CONNECTION',
|
||||
'DYNAMICCONNECTION',
|
||||
'BANDWIDTH',
|
||||
'HEALTH',
|
||||
'NONE',
|
||||
]
|
||||
),
|
||||
sopersistence=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'ENABLED',
|
||||
'DISABLED',
|
||||
]
|
||||
),
|
||||
sopersistencetimeout=dict(type='float'),
|
||||
sothreshold=dict(type='float'),
|
||||
sobackupaction=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'DROP',
|
||||
'ACCEPT',
|
||||
'REDIRECT',
|
||||
]
|
||||
),
|
||||
appflowlog=dict(
|
||||
type='str',
|
||||
choices=[
|
||||
'ENABLED',
|
||||
'DISABLED',
|
||||
]
|
||||
),
|
||||
domainname=dict(type='str'),
|
||||
cookie_domain=dict(type='str'),
|
||||
)
|
||||
|
||||
hand_inserted_arguments = dict(
|
||||
domain_bindings=dict(type='list'),
|
||||
service_bindings=dict(type='list'),
|
||||
disabled=dict(
|
||||
type='bool',
|
||||
default=False,
|
||||
),
|
||||
)
|
||||
|
||||
argument_spec = dict()
|
||||
|
||||
argument_spec.update(netscaler_common_arguments)
|
||||
argument_spec.update(module_specific_arguments)
|
||||
argument_spec.update(hand_inserted_arguments)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module_result = dict(
|
||||
changed=False,
|
||||
failed=False,
|
||||
loglines=loglines,
|
||||
)
|
||||
|
||||
# Fail the module if imports failed
|
||||
if not PYTHON_SDK_IMPORTED:
|
||||
module.fail_json(msg='Could not load nitro python sdk')
|
||||
|
||||
# Fallthrough to rest of execution
|
||||
client = get_nitro_client(module)
|
||||
|
||||
try:
|
||||
client.login()
|
||||
except nitro_exception as e:
|
||||
msg = "nitro exception during login. errorcode=%s, message=%s" % (str(e.errorcode), e.message)
|
||||
module.fail_json(msg=msg)
|
||||
except Exception as e:
|
||||
if str(type(e)) == "<class 'requests.exceptions.ConnectionError'>":
|
||||
module.fail_json(msg='Connection error %s' % str(e))
|
||||
elif str(type(e)) == "<class 'requests.exceptions.SSLError'>":
|
||||
module.fail_json(msg='SSL Error %s' % str(e))
|
||||
else:
|
||||
module.fail_json(msg='Unexpected error during login %s' % str(e))
|
||||
|
||||
readwrite_attrs = [
|
||||
'name',
|
||||
'servicetype',
|
||||
'dnsrecordtype',
|
||||
'lbmethod',
|
||||
'backuplbmethod',
|
||||
'netmask',
|
||||
'v6netmasklen',
|
||||
'tolerance',
|
||||
'persistencetype',
|
||||
'persistenceid',
|
||||
'persistmask',
|
||||
'v6persistmasklen',
|
||||
'timeout',
|
||||
'mir',
|
||||
'disableprimaryondown',
|
||||
'dynamicweight',
|
||||
'considereffectivestate',
|
||||
'comment',
|
||||
'somethod',
|
||||
'sopersistence',
|
||||
'sopersistencetimeout',
|
||||
'sothreshold',
|
||||
'sobackupaction',
|
||||
'appflowlog',
|
||||
'cookie_domain',
|
||||
]
|
||||
|
||||
readonly_attrs = [
|
||||
'curstate',
|
||||
'status',
|
||||
'lbrrreason',
|
||||
'iscname',
|
||||
'sitepersistence',
|
||||
'totalservices',
|
||||
'activeservices',
|
||||
'statechangetimesec',
|
||||
'statechangetimemsec',
|
||||
'tickssincelaststatechange',
|
||||
'health',
|
||||
'policyname',
|
||||
'priority',
|
||||
'gotopriorityexpression',
|
||||
'type',
|
||||
'vsvrbindsvcip',
|
||||
'vsvrbindsvcport',
|
||||
'__count',
|
||||
]
|
||||
|
||||
immutable_attrs = [
|
||||
'name',
|
||||
'servicetype',
|
||||
]
|
||||
|
||||
# Instantiate config proxy
|
||||
gslb_vserver_proxy = ConfigProxy(
|
||||
actual=gslbvserver(),
|
||||
client=client,
|
||||
attribute_values_dict=module.params,
|
||||
readwrite_attrs=readwrite_attrs,
|
||||
readonly_attrs=readonly_attrs,
|
||||
immutable_attrs=immutable_attrs,
|
||||
)
|
||||
|
||||
try:
|
||||
ensure_feature_is_enabled(client, 'GSLB')
|
||||
# Apply appropriate state
|
||||
if module.params['state'] == 'present':
|
||||
log('Applying state present')
|
||||
if not gslb_vserver_exists(client, module):
|
||||
log('Creating object')
|
||||
if not module.check_mode:
|
||||
gslb_vserver_proxy.add()
|
||||
sync_domain_bindings(client, module)
|
||||
sync_service_bindings(client, module)
|
||||
if module.params['save_config']:
|
||||
client.save_config()
|
||||
module_result['changed'] = True
|
||||
elif not all_identical(client, module, gslb_vserver_proxy):
|
||||
log('Entering update actions')
|
||||
|
||||
# Check if we try to change value of immutable attributes
|
||||
if not gslb_vserver_identical(client, module, gslb_vserver_proxy):
|
||||
log('Updating gslb vserver')
|
||||
immutables_changed = get_immutables_intersection(gslb_vserver_proxy, diff_list(client, module, gslb_vserver_proxy).keys())
|
||||
if immutables_changed != []:
|
||||
module.fail_json(
|
||||
msg='Cannot update immutable attributes %s' % (immutables_changed,),
|
||||
diff=diff_list(client, module, gslb_vserver_proxy),
|
||||
**module_result
|
||||
)
|
||||
if not module.check_mode:
|
||||
gslb_vserver_proxy.update()
|
||||
|
||||
# Update domain bindings
|
||||
if not domain_bindings_identical(client, module):
|
||||
if not module.check_mode:
|
||||
sync_domain_bindings(client, module)
|
||||
|
||||
# Update service bindings
|
||||
if not service_bindings_identical(client, module):
|
||||
if not module.check_mode:
|
||||
sync_service_bindings(client, module)
|
||||
|
||||
module_result['changed'] = True
|
||||
if not module.check_mode:
|
||||
if module.params['save_config']:
|
||||
client.save_config()
|
||||
else:
|
||||
module_result['changed'] = False
|
||||
|
||||
if not module.check_mode:
|
||||
res = do_state_change(client, module, gslb_vserver_proxy)
|
||||
if res.errorcode != 0:
|
||||
msg = 'Error when setting disabled state. errorcode: %s message: %s' % (res.errorcode, res.message)
|
||||
module.fail_json(msg=msg, **module_result)
|
||||
|
||||
# Sanity check for state
|
||||
if not module.check_mode:
|
||||
if not gslb_vserver_exists(client, module):
|
||||
module.fail_json(msg='GSLB Vserver does not exist', **module_result)
|
||||
if not gslb_vserver_identical(client, module, gslb_vserver_proxy):
|
||||
module.fail_json(msg='GSLB Vserver differs from configured', diff=diff_list(client, module, gslb_vserver_proxy), **module_result)
|
||||
if not domain_bindings_identical(client, module):
|
||||
module.fail_json(msg='Domain bindings differ from configured', diff=diff_list(client, module, gslb_vserver_proxy), **module_result)
|
||||
if not service_bindings_identical(client, module):
|
||||
module.fail_json(msg='Service bindings differ from configured', diff=diff_list(client, module, gslb_vserver_proxy), **module_result)
|
||||
|
||||
elif module.params['state'] == 'absent':
|
||||
|
||||
if gslb_vserver_exists(client, module):
|
||||
if not module.check_mode:
|
||||
gslb_vserver_proxy.delete()
|
||||
if module.params['save_config']:
|
||||
client.save_config()
|
||||
module_result['changed'] = True
|
||||
else:
|
||||
module_result['changed'] = False
|
||||
|
||||
# Sanity check for state
|
||||
if not module.check_mode:
|
||||
if gslb_vserver_exists(client, module):
|
||||
module.fail_json(msg='GSLB Vserver still exists', **module_result)
|
||||
|
||||
except nitro_exception as e:
|
||||
msg = "nitro exception errorcode=%s, message=%s" % (str(e.errorcode), e.message)
|
||||
module.fail_json(msg=msg, **module_result)
|
||||
|
||||
client.logout()
|
||||
module.exit_json(**module_result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
testcase: "*"
|
||||
test_cases: []
|
||||
|
||||
nitro_user: nsroot
|
||||
nitro_pass: nsroot
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
|
||||
- { include: testbed.yaml, state: present }
|
||||
|
||||
- { include: nitro.yaml, tags: ['nitro'] }
|
||||
|
||||
- { include: testbed.yaml, state: absent }
|
|
@ -0,0 +1,14 @@
|
|||
- name: collect all nitro test cases
|
||||
find:
|
||||
paths: "{{ role_path }}/tests/nitro"
|
||||
patterns: "{{ testcase }}.yaml"
|
||||
register: test_cases
|
||||
|
||||
- name: set test_items
|
||||
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
|
||||
|
||||
- name: run test case
|
||||
include: "{{ test_case_to_run }}"
|
||||
with_items: "{{ test_items }}"
|
||||
loop_control:
|
||||
loop_var: test_case_to_run
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
|
||||
- name: Setup gslb site
|
||||
netscaler_gslb_site:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
state: "{{ state }}"
|
||||
|
||||
sitename: gslb-site-1
|
||||
siteipaddress: 192.168.1.1
|
||||
sitetype: LOCAL
|
||||
publicip: 192.168.1.1
|
||||
metricexchange: ENABLED
|
||||
nwmetricexchange: ENABLED
|
||||
sessionexchange: ENABLED
|
||||
triggermonitor: ALWAYS
|
||||
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
|
||||
- name: Setup gslb service
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
|
||||
netscaler_gslb_service:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
state: "{{ state }}"
|
||||
|
||||
servicename: gslb-service-1
|
||||
servicetype: HTTP
|
||||
sitename: gslb-site-1
|
||||
ipaddress: 10.10.10.11
|
||||
port: 80
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/flap_disabled/setup.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/flap_disabled/remove.yaml"
|
||||
vars:
|
||||
check_mode: no
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
|
||||
- name: remove http lb vserver
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
delegate_to: localhost
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
state: absent
|
||||
name: gslb-vserver-2
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
|
||||
- name: flap gslb vserver
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
delegate_to: localhost
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-2
|
||||
servicetype: HTTP
|
||||
lbmethod: SOURCEIPHASH
|
||||
netmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
||||
|
||||
disabled: "{{ item|int % 2 }}"
|
||||
with_sequence: count=20
|
||||
delay: 1
|
||||
|
||||
- name: flap gslb vserver
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
delegate_to: localhost
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-2
|
||||
servicetype: HTTP
|
||||
lbmethod: SOURCEIPHASH
|
||||
netmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
||||
|
||||
disabled: "{{ item|int % 2 }}"
|
||||
with_sequence: count=20
|
||||
delay: 5
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/setup.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/setup.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/setup.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/setup.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_domainbinding.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_domainbinding.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_domainbinding.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_domainbinding.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_gslbservice_binding.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_gslbservice_binding.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_gslbservice_binding.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/update_gslbservice_binding.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/remove.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/remove.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/remove.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/http/remove.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
|
||||
- name: Remove gslb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
state: absent
|
||||
|
||||
name: gslb-vserver-1
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
|
||||
- name: Setup gslb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-1
|
||||
servicetype: HTTP
|
||||
dnsrecordtype: A
|
||||
lbmethod: ROUNDROBIN
|
||||
backuplbmethod: RTT
|
||||
tolerance: 50
|
||||
persistencetype: NONE
|
||||
persistenceid: 500
|
||||
persistmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
||||
timeout: 1000
|
||||
mir: DISABLED
|
||||
disableprimaryondown: DISABLED
|
||||
dynamicweight: DISABLED
|
||||
considereffectivestate: NONE
|
||||
comment: some comment
|
||||
somethod: CONNECTION
|
||||
sopersistence: DISABLED
|
||||
sopersistencetimeout: 100
|
||||
sothreshold: 5000
|
||||
sobackupaction: DROP
|
||||
appflowlog: DISABLED
|
||||
|
||||
domain_bindings:
|
||||
- domainname: example.com
|
||||
cookietimeout: 100
|
||||
backupip: 10.10.10.10
|
||||
ttl: 100
|
||||
sitedomainttl: 200
|
||||
|
||||
service_bindings:
|
||||
- weight: 100
|
||||
servicename: gslb-service-1
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
|
||||
- name: Setup gslb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-1
|
||||
servicetype: HTTP
|
||||
dnsrecordtype: A
|
||||
lbmethod: ROUNDROBIN
|
||||
backuplbmethod: RTT
|
||||
tolerance: 50
|
||||
persistencetype: NONE
|
||||
persistenceid: 500
|
||||
persistmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
||||
timeout: 500
|
||||
mir: DISABLED
|
||||
disableprimaryondown: DISABLED
|
||||
dynamicweight: DISABLED
|
||||
considereffectivestate: NONE
|
||||
comment: some comment
|
||||
somethod: CONNECTION
|
||||
sopersistence: DISABLED
|
||||
sopersistencetimeout: 100
|
||||
sothreshold: 5000
|
||||
sobackupaction: DROP
|
||||
appflowlog: DISABLED
|
||||
|
||||
domain_bindings:
|
||||
- domainname: example.com
|
||||
cookietimeout: 100
|
||||
backupip: 10.10.10.10
|
||||
ttl: 100
|
||||
sitedomainttl: 200
|
||||
|
||||
service_bindings:
|
||||
- weight: 100
|
||||
servicename: gslb-service-1
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
|
||||
- name: Setup gslb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-1
|
||||
servicetype: HTTP
|
||||
dnsrecordtype: A
|
||||
lbmethod: ROUNDROBIN
|
||||
backuplbmethod: RTT
|
||||
tolerance: 50
|
||||
persistencetype: NONE
|
||||
persistenceid: 500
|
||||
persistmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
||||
timeout: 500
|
||||
mir: DISABLED
|
||||
disableprimaryondown: DISABLED
|
||||
dynamicweight: DISABLED
|
||||
considereffectivestate: NONE
|
||||
comment: some comment
|
||||
somethod: CONNECTION
|
||||
sopersistence: DISABLED
|
||||
sopersistencetimeout: 100
|
||||
sothreshold: 5000
|
||||
sobackupaction: DROP
|
||||
appflowlog: DISABLED
|
||||
|
||||
domain_bindings:
|
||||
- domainname: anotherexample.com
|
||||
cookietimeout: 100
|
||||
backupip: 10.10.10.10
|
||||
ttl: 100
|
||||
sitedomainttl: 200
|
||||
|
||||
service_bindings:
|
||||
- weight: 100
|
||||
servicename: gslb-service-1
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
|
||||
- name: Setup gslb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-1
|
||||
servicetype: HTTP
|
||||
dnsrecordtype: A
|
||||
lbmethod: ROUNDROBIN
|
||||
backuplbmethod: RTT
|
||||
tolerance: 50
|
||||
persistencetype: NONE
|
||||
persistenceid: 500
|
||||
persistmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
||||
timeout: 500
|
||||
mir: DISABLED
|
||||
disableprimaryondown: DISABLED
|
||||
dynamicweight: DISABLED
|
||||
considereffectivestate: NONE
|
||||
comment: some comment
|
||||
somethod: CONNECTION
|
||||
sopersistence: DISABLED
|
||||
sopersistencetimeout: 100
|
||||
sothreshold: 5000
|
||||
sobackupaction: DROP
|
||||
appflowlog: DISABLED
|
||||
|
||||
domain_bindings:
|
||||
- domainname: example.com
|
||||
cookietimeout: 100
|
||||
backupip: 10.10.10.10
|
||||
ttl: 200
|
||||
sitedomainttl: 200
|
||||
|
||||
service_bindings:
|
||||
- weight: 50
|
||||
servicename: gslb-service-1
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/setup.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/setup.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/setup.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/setup.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/remove.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/remove.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/remove.yaml"
|
||||
vars:
|
||||
check_mode: yes
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
||||
|
||||
- include: "{{ role_path }}/tests/nitro/sourceiphash/remove.yaml"
|
||||
vars:
|
||||
check_mode: no
|
||||
|
||||
- assert:
|
||||
that: not result|changed
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
|
||||
- name: Remove sourceiphash glsb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
state: absent
|
||||
|
||||
name: gslb-vserver-2
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
|
||||
- name: Setup sourceiphash gslb vserver
|
||||
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
check_mode: "{{ check_mode }}"
|
||||
|
||||
netscaler_gslb_vserver:
|
||||
nitro_user: "{{nitro_user}}"
|
||||
nitro_pass: "{{nitro_pass}}"
|
||||
nsip: "{{nsip}}"
|
||||
|
||||
name: gslb-vserver-2
|
||||
servicetype: HTTP
|
||||
lbmethod: SOURCEIPHASH
|
||||
netmask: 255.255.255.0
|
||||
v6persistmasklen: 128
|
|
@ -0,0 +1,753 @@
|
|||
|
||||
# Copyright (c) 2017 Citrix Systems
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
from ansible.compat.tests.mock import patch, Mock, MagicMock, call
|
||||
from .netscaler_module import TestModule, nitro_base_patcher, set_module_args
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info[:2] != (2, 6):
|
||||
import requests
|
||||
|
||||
|
||||
class TestNetscalerGSLBVserverModule(TestModule):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
class MockException(Exception):
|
||||
pass
|
||||
|
||||
cls.MockException = MockException
|
||||
|
||||
m = MagicMock()
|
||||
nssrc_modules_mock = {
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb': m,
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver': m,
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver.gslbvserver': m,
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_gslbservice_binding': m,
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_gslbservice_binding.gslbvserver_gslbservice_binding': m,
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_domain_binding': m,
|
||||
'nssrc.com.citrix.netscaler.nitro.resource.config.gslb.gslbvserver_domain_binding.gslbvserver_domain_binding': m,
|
||||
}
|
||||
|
||||
cls.nitro_specific_patcher = patch.dict(sys.modules, nssrc_modules_mock)
|
||||
cls.nitro_base_patcher = nitro_base_patcher
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.nitro_base_patcher.stop()
|
||||
cls.nitro_specific_patcher.stop()
|
||||
|
||||
def setUp(self):
|
||||
self.nitro_base_patcher.start()
|
||||
self.nitro_specific_patcher.start()
|
||||
|
||||
# Setup minimal required arguments to pass AnsibleModule argument parsing
|
||||
|
||||
def tearDown(self):
|
||||
self.nitro_base_patcher.stop()
|
||||
self.nitro_specific_patcher.stop()
|
||||
|
||||
def test_graceful_nitro_api_import_error(self):
|
||||
# Stop nitro api patching to cause ImportError
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
self.nitro_base_patcher.stop()
|
||||
self.nitro_specific_patcher.stop()
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'Could not load nitro python sdk')
|
||||
|
||||
def test_graceful_nitro_error_on_login(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
class MockException(Exception):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.errorcode = 0
|
||||
self.message = ''
|
||||
|
||||
client_mock = Mock()
|
||||
client_mock.login = Mock(side_effect=MockException)
|
||||
m = Mock(return_value=client_mock)
|
||||
with patch('ansible.modules.network.netscaler.netscaler_gslb_vserver.get_nitro_client', m):
|
||||
with patch('ansible.modules.network.netscaler.netscaler_gslb_vserver.nitro_exception', MockException):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertTrue(result['msg'].startswith('nitro exception'), msg='nitro exception during login not handled properly')
|
||||
|
||||
def test_graceful_no_connection_error(self):
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
self.skipTest('requests library not available under python2.6')
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
class MockException(Exception):
|
||||
pass
|
||||
client_mock = Mock()
|
||||
attrs = {'login.side_effect': requests.exceptions.ConnectionError}
|
||||
client_mock.configure_mock(**attrs)
|
||||
m = Mock(return_value=client_mock)
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
nitro_exception=MockException,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertTrue(result['msg'].startswith('Connection error'), msg='Connection error was not handled gracefully')
|
||||
|
||||
def test_graceful_login_error(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
self.skipTest('requests library not available under python2.6')
|
||||
|
||||
class MockException(Exception):
|
||||
pass
|
||||
client_mock = Mock()
|
||||
attrs = {'login.side_effect': requests.exceptions.SSLError}
|
||||
client_mock.configure_mock(**attrs)
|
||||
m = Mock(return_value=client_mock)
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
nitro_exception=MockException,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertTrue(result['msg'].startswith('SSL Error'), msg='SSL Error was not handled gracefully')
|
||||
|
||||
def test_ensure_feature_is_enabled_called(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
gslb_service_proxy_mock = Mock()
|
||||
ensure_feature_is_enabled_mock = Mock()
|
||||
client_mock = Mock()
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=Mock(return_value=client_mock),
|
||||
gslb_vserver_exists=Mock(side_effect=[False, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True]),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=ensure_feature_is_enabled_mock,
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
ConfigProxy=Mock(return_value=gslb_service_proxy_mock),
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
ensure_feature_is_enabled_mock.assert_called_with(client_mock, 'GSLB')
|
||||
|
||||
def test_save_config_called_on_state_present(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
gslb_service_proxy_mock = Mock()
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
gslb_vserver_exists=Mock(side_effect=[False, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=Mock(return_value=gslb_service_proxy_mock),
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
self.assertIn(call.save_config(), client_mock.mock_calls)
|
||||
|
||||
def test_save_config_called_on_state_absent(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='absent',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
gslb_service_proxy_mock = Mock()
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
gslb_vserver_exists=Mock(side_effect=[True, False]),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=Mock(return_value=gslb_service_proxy_mock),
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
self.assertIn(call.save_config(), client_mock.mock_calls)
|
||||
|
||||
def test_save_config_not_called_on_state_present(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
save_config=False,
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
gslb_service_proxy_mock = Mock()
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
gslb_vserver_exists=Mock(side_effect=[False, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True]),
|
||||
nitro_exception=self.MockException,
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=Mock(return_value=gslb_service_proxy_mock),
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
self.assertNotIn(call.save_config(), client_mock.mock_calls)
|
||||
|
||||
def test_save_config_not_called_on_state_absent(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='absent',
|
||||
save_config=False,
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
gslb_service_proxy_mock = Mock()
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
gslb_vserver_exists=Mock(side_effect=[True, False]),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=Mock(return_value=gslb_service_proxy_mock),
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
self.assertNotIn(call.save_config(), client_mock.mock_calls)
|
||||
|
||||
def test_new_gslb_vserver_execution_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
gslb_vserver_exists=Mock(side_effect=[False, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True]),
|
||||
nitro_exception=self.MockException,
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
gslb_service_proxy_mock.assert_has_calls([call.add()])
|
||||
|
||||
def test_modified_gslb_vserver_execution_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, False, True]),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
domain_bindings_identical=Mock(side_effect=[True, True, True]),
|
||||
service_bindings_identical=Mock(side_effect=[True, True, True]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
nitro_exception=self.MockException,
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
gslb_service_proxy_mock.assert_has_calls([call.update()])
|
||||
|
||||
def test_absent_gslb_vserver_execution_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='absent',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, False]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, True]),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
gslb_service_proxy_mock.assert_has_calls([call.delete()])
|
||||
|
||||
def test_present_gslb_vserver_identical_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True, True]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
gslb_service_proxy_mock.assert_not_called()
|
||||
|
||||
def test_present_gslb_vserver_domain_bindings_error_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True, True, True]),
|
||||
domain_bindings_identical=Mock(side_effect=[False, False, False]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'Domain bindings differ from configured')
|
||||
self.assertTrue(result['failed'])
|
||||
|
||||
def test_present_gslb_vserver_service_bindings_error_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[True, True, True]),
|
||||
service_bindings_identical=Mock(side_effect=[False, False, False]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'Service bindings differ from configured')
|
||||
self.assertTrue(result['failed'])
|
||||
|
||||
def test_absent_gslb_vserver_noop_flow(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='absent',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[False, False]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, False]),
|
||||
nitro_exception=self.MockException,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
self.exited()
|
||||
gslb_service_proxy_mock.assert_not_called()
|
||||
|
||||
def test_present_gslb_vserver_failed_update(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
nitro_exception=self.MockException,
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, False, False]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'GSLB Vserver differs from configured')
|
||||
self.assertTrue(result['failed'])
|
||||
|
||||
def test_present_gslb_vserver_failed_create(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
nitro_exception=self.MockException,
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
do_state_change=Mock(return_value=Mock(errorcode=0)),
|
||||
gslb_vserver_exists=Mock(side_effect=[False, False]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, False]),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'GSLB Vserver does not exist')
|
||||
self.assertTrue(result['failed'])
|
||||
|
||||
def test_present_gslb_vserver_update_immutable_attribute(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
nitro_exception=self.MockException,
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=['domain']),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, False]),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'Cannot update immutable attributes [\'domain\']')
|
||||
self.assertTrue(result['failed'])
|
||||
|
||||
def test_absent_gslb_vserver_failed_delete(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='absent',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
client_mock = Mock()
|
||||
|
||||
m = Mock(return_value=client_mock)
|
||||
|
||||
glsb_service_proxy_attrs = {
|
||||
'diff_object.return_value': {},
|
||||
}
|
||||
gslb_service_proxy_mock = Mock()
|
||||
gslb_service_proxy_mock.configure_mock(**glsb_service_proxy_attrs)
|
||||
config_proxy_mock = Mock(return_value=gslb_service_proxy_mock)
|
||||
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
nitro_exception=self.MockException,
|
||||
get_nitro_client=m,
|
||||
diff_list=Mock(return_value={}),
|
||||
get_immutables_intersection=Mock(return_value=[]),
|
||||
gslb_vserver_exists=Mock(side_effect=[True, True]),
|
||||
gslb_vserver_identical=Mock(side_effect=[False, False]),
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
ConfigProxy=config_proxy_mock,
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertEqual(result['msg'], 'GSLB Vserver still exists')
|
||||
self.assertTrue(result['failed'])
|
||||
|
||||
def test_graceful_nitro_exception_state_present(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='present',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
class MockException(Exception):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.errorcode = 0
|
||||
self.message = ''
|
||||
|
||||
m = Mock(side_effect=MockException)
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
gslb_vserver_exists=m,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
nitro_exception=MockException
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertTrue(
|
||||
result['msg'].startswith('nitro exception'),
|
||||
msg='Nitro exception not caught on operation absent'
|
||||
)
|
||||
|
||||
def test_graceful_nitro_exception_state_absent(self):
|
||||
set_module_args(dict(
|
||||
nitro_user='user',
|
||||
nitro_pass='pass',
|
||||
nsip='1.1.1.1',
|
||||
state='absent',
|
||||
))
|
||||
from ansible.modules.network.netscaler import netscaler_gslb_vserver
|
||||
|
||||
class MockException(Exception):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.errorcode = 0
|
||||
self.message = ''
|
||||
|
||||
m = Mock(side_effect=MockException)
|
||||
with patch.multiple(
|
||||
'ansible.modules.network.netscaler.netscaler_gslb_vserver',
|
||||
gslb_vserver_exists=m,
|
||||
ensure_feature_is_enabled=Mock(),
|
||||
nitro_exception=MockException
|
||||
):
|
||||
self.module = netscaler_gslb_vserver
|
||||
result = self.failed()
|
||||
self.assertTrue(
|
||||
result['msg'].startswith('nitro exception'),
|
||||
msg='Nitro exception not caught on operation absent'
|
||||
)
|
Loading…
Reference in a new issue