Various f5 fixes (#44858)
* Remove sdk from modules * Correct IP address bugs in data_group * Correct compare_dictionary bug in several modules
This commit is contained in:
parent
773c0982b0
commit
5bdcaff921
8 changed files with 359 additions and 284 deletions
|
@ -335,28 +335,34 @@ def transform_name(partition='', name='', sub_path=''):
|
|||
return result
|
||||
|
||||
|
||||
def dict2tuple(items):
|
||||
"""Convert a dictionary to a list of tuples
|
||||
def compare_complex_list(want, have):
|
||||
"""Performs a complex list comparison
|
||||
|
||||
This method is used in cases where dictionaries need to be compared. Due
|
||||
to dictionaries inherently having no order, it is easier to compare list
|
||||
of tuples because these lists can be converted to sets.
|
||||
|
||||
This conversion only supports dicts of simple values. Do not give it dicts
|
||||
that contain sub-dicts. This will not give you the result you want when using
|
||||
the returned tuple for comparison.
|
||||
A complex list is a list of dictionaries
|
||||
|
||||
Args:
|
||||
items (dict): The dictionary of items that should be converted
|
||||
want (list): List of dictionaries to compare with second parameter.
|
||||
have (list): List of dictionaries compare with first parameter.
|
||||
|
||||
Returns:
|
||||
list: Returns a list of tuples upon success. Otherwise, an empty list.
|
||||
bool:
|
||||
"""
|
||||
result = []
|
||||
for x in items:
|
||||
if want == [] and have is None:
|
||||
return None
|
||||
if want is None:
|
||||
return None
|
||||
w = []
|
||||
h = []
|
||||
for x in want:
|
||||
tmp = [(str(k), str(v)) for k, v in iteritems(x)]
|
||||
result += tmp
|
||||
return result
|
||||
w += tmp
|
||||
for x in have:
|
||||
tmp = [(str(k), str(v)) for k, v in iteritems(x)]
|
||||
h += tmp
|
||||
if set(w) == set(h):
|
||||
return None
|
||||
else:
|
||||
return want
|
||||
|
||||
|
||||
def compare_dictionary(want, have):
|
||||
|
@ -369,12 +375,12 @@ def compare_dictionary(want, have):
|
|||
Returns:
|
||||
bool:
|
||||
"""
|
||||
if want == [] and have is None:
|
||||
if want == {} and have is None:
|
||||
return None
|
||||
if want is None:
|
||||
return None
|
||||
w = dict2tuple(want)
|
||||
h = dict2tuple(have)
|
||||
w = [(str(k), str(v)) for k, v in iteritems(want)]
|
||||
h = [(str(k), str(v)) for k, v in iteritems(have)]
|
||||
if set(w) == set(h):
|
||||
return None
|
||||
else:
|
||||
|
|
|
@ -265,7 +265,7 @@ try:
|
|||
from library.module_utils.network.f5.common import F5ModuleError
|
||||
from library.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from library.module_utils.network.f5.common import cleanup_tokens
|
||||
from library.module_utils.network.f5.common import compare_dictionary
|
||||
from library.module_utils.network.f5.common import compare_complex_list
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
from library.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
from library.module_utils.network.f5.ipaddress import is_valid_ip_network
|
||||
|
@ -283,7 +283,7 @@ except ImportError:
|
|||
from ansible.module_utils.network.f5.common import F5ModuleError
|
||||
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from ansible.module_utils.network.f5.common import cleanup_tokens
|
||||
from ansible.module_utils.network.f5.common import compare_dictionary
|
||||
from ansible.module_utils.network.f5.common import compare_complex_list
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
from ansible.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
from ansible.module_utils.network.f5.ipaddress import is_valid_ip_network
|
||||
|
@ -351,32 +351,23 @@ class RecordsEncoder(object):
|
|||
return self.encode_string_from_dict(record)
|
||||
|
||||
def encode_address_from_dict(self, record):
|
||||
if is_valid_ip_network(record['key']):
|
||||
key = ip_network(u"{0}".format(str(record['key'])))
|
||||
elif is_valid_ip(record['key']):
|
||||
key = ip_address(u"{0}".format(str(record['key'])))
|
||||
elif is_valid_ip_interface(record['key']):
|
||||
if is_valid_ip_interface(record['key']):
|
||||
key = ip_interface(u"{0}".format(str(record['key'])))
|
||||
else:
|
||||
raise F5ModuleError(
|
||||
"When specifying an 'address' type, the value to the left of the separator must be an IP."
|
||||
)
|
||||
if key and 'value' in record:
|
||||
try:
|
||||
# Only ip_address's have max_prefixlen
|
||||
if key.max_prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key), record['value'])
|
||||
except ValueError:
|
||||
if key.network.prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key.ip), record['value'])
|
||||
return self.encode_network(
|
||||
str(key.network_address), key.prefixlen, record['value'])
|
||||
str(key.network.network_address), key.network.prefixlen, record['value']
|
||||
)
|
||||
elif key:
|
||||
try:
|
||||
# Only ip_address's have max_prefixlen
|
||||
if key.max_prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key), str(key))
|
||||
except ValueError:
|
||||
if key.network.prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key.ip), str(key.ip))
|
||||
return self.encode_network(
|
||||
str(key.network_address), key.prefixlen, str(key.network_address)
|
||||
str(key.network.network_address), key.network.prefixlen, str(key.network.network_address)
|
||||
)
|
||||
|
||||
def encode_integer_from_dict(self, record):
|
||||
|
@ -419,35 +410,25 @@ class RecordsEncoder(object):
|
|||
# 192.168.0.0/16 := "Network3",
|
||||
# 2402:9400:1000:0::/64 := "Network4",
|
||||
parts = record.split(self._separator)
|
||||
if is_valid_ip_network(parts[0]):
|
||||
key = ip_network(u"{0}".format(str(parts[0])))
|
||||
elif is_valid_ip(parts[0]):
|
||||
key = ip_address(u"{0}".format(str(parts[0])))
|
||||
elif is_valid_ip_interface(parts[0]):
|
||||
key = ip_interface(u"{0}".format(str(parts[0])))
|
||||
elif parts[0] == '':
|
||||
pass
|
||||
else:
|
||||
if parts[0] == '':
|
||||
return
|
||||
if not is_valid_ip_interface(parts[0]):
|
||||
raise F5ModuleError(
|
||||
"When specifying an 'address' type, the value to the left of the separator must be an IP."
|
||||
)
|
||||
key = ip_interface(u"{0}".format(str(parts[0])))
|
||||
|
||||
if len(parts) == 2:
|
||||
try:
|
||||
# Only ip_address's have max_prefixlen
|
||||
if key.max_prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key), parts[1])
|
||||
except ValueError:
|
||||
if key.network.prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key.ip), parts[1])
|
||||
return self.encode_network(
|
||||
str(key.network_address), key.prefixlen, parts[1])
|
||||
str(key.network.network_address), key.network.prefixlen, parts[1]
|
||||
)
|
||||
elif len(parts) == 1 and parts[0] != '':
|
||||
try:
|
||||
# Only ip_address's have max_prefixlen
|
||||
if key.max_prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key), str(key))
|
||||
except ValueError:
|
||||
if key.network.prefixlen in [32, 128]:
|
||||
return self.encode_host(str(key.ip), str(key.ip))
|
||||
return self.encode_network(
|
||||
str(key.network_address), key.prefixlen, str(key.network_address)
|
||||
str(key.network.network_address), key.network.prefixlen, str(key.network.network_address)
|
||||
)
|
||||
|
||||
def encode_host(self, key, value):
|
||||
|
@ -706,7 +687,7 @@ class Difference(object):
|
|||
return None
|
||||
if self.have.records is None:
|
||||
return self.want.records
|
||||
result = compare_dictionary(self.want.records, self.have.records)
|
||||
result = compare_complex_list(self.want.records, self.have.records)
|
||||
return result
|
||||
|
||||
@property
|
||||
|
|
|
@ -415,7 +415,7 @@ class Difference(object):
|
|||
)
|
||||
result = dict()
|
||||
|
||||
different = compare_dictionary([self.want.variables], [self.have.variables])
|
||||
different = compare_dictionary(self.want.variables, self.have.variables)
|
||||
if not different:
|
||||
return None
|
||||
|
||||
|
|
|
@ -244,13 +244,14 @@ from ansible.module_utils.basic import AnsibleModule
|
|||
from ansible.module_utils.basic import env_fallback
|
||||
|
||||
try:
|
||||
from library.module_utils.compat.ipaddress import ip_address
|
||||
from library.module_utils.network.f5.bigip import HAS_F5SDK
|
||||
from library.module_utils.network.f5.bigip import F5Client
|
||||
from library.module_utils.network.f5.common import F5ModuleError
|
||||
from library.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from library.module_utils.network.f5.common import cleanup_tokens
|
||||
from library.module_utils.network.f5.common import fq_name
|
||||
from library.module_utils.network.f5.common import compare_dictionary
|
||||
from library.module_utils.network.f5.common import compare_complex_list
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
from library.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
from library.module_utils.network.f5.ipaddress import validate_ip_v6_address
|
||||
|
@ -260,13 +261,14 @@ try:
|
|||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
except ImportError:
|
||||
from ansible.module_utils.compat.ipaddress import ip_address
|
||||
from ansible.module_utils.network.f5.bigip import HAS_F5SDK
|
||||
from ansible.module_utils.network.f5.bigip import F5Client
|
||||
from ansible.module_utils.network.f5.common import F5ModuleError
|
||||
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from ansible.module_utils.network.f5.common import cleanup_tokens
|
||||
from ansible.module_utils.network.f5.common import fq_name
|
||||
from ansible.module_utils.network.f5.common import compare_dictionary
|
||||
from ansible.module_utils.network.f5.common import compare_complex_list
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
from ansible.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address
|
||||
|
@ -534,7 +536,8 @@ class ModuleParameters(Parameters):
|
|||
if self._values['address'] is None:
|
||||
return None
|
||||
if is_valid_ip(self._values['address']):
|
||||
return self._values['address']
|
||||
ip = str(ip_address(u'{0}'.format(self._values['address'])))
|
||||
return ip
|
||||
raise F5ModuleError(
|
||||
"Specified 'address' is not an IP address."
|
||||
)
|
||||
|
@ -758,7 +761,8 @@ class Difference(object):
|
|||
return None
|
||||
if self.want.virtual_server_dependencies is None:
|
||||
return None
|
||||
return compare_dictionary(self.want.virtual_server_dependencies, self.have.virtual_server_dependencies)
|
||||
result = compare_complex_list(self.want.virtual_server_dependencies, self.have.virtual_server_dependencies)
|
||||
return result
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
@ -159,7 +158,6 @@ timeout:
|
|||
sample: 10
|
||||
'''
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
@ -167,33 +165,29 @@ from ansible.module_utils.basic import env_fallback
|
|||
from ansible.module_utils.six import iteritems
|
||||
|
||||
try:
|
||||
from library.module_utils.network.f5.bigip import HAS_F5SDK
|
||||
from library.module_utils.network.f5.bigip import F5Client
|
||||
from library.module_utils.network.f5.bigip import F5RestClient
|
||||
from library.module_utils.network.f5.common import F5ModuleError
|
||||
from library.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from library.module_utils.network.f5.common import cleanup_tokens
|
||||
from library.module_utils.network.f5.common import fq_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
from library.module_utils.network.f5.common import transform_name
|
||||
from library.module_utils.network.f5.common import exit_json
|
||||
from library.module_utils.network.f5.common import fail_json
|
||||
from library.module_utils.network.f5.common import compare_dictionary
|
||||
from library.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
except ImportError:
|
||||
from ansible.module_utils.network.f5.bigip import HAS_F5SDK
|
||||
from ansible.module_utils.network.f5.bigip import F5Client
|
||||
from ansible.module_utils.network.f5.bigip import F5RestClient
|
||||
from ansible.module_utils.network.f5.common import F5ModuleError
|
||||
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from ansible.module_utils.network.f5.common import cleanup_tokens
|
||||
from ansible.module_utils.network.f5.common import fq_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
from ansible.module_utils.network.f5.common import transform_name
|
||||
from ansible.module_utils.network.f5.common import compare_dictionary
|
||||
from ansible.module_utils.network.f5.common import exit_json
|
||||
from ansible.module_utils.network.f5.common import fail_json
|
||||
from ansible.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
|
@ -201,33 +195,24 @@ class Parameters(AnsibleF5Parameters):
|
|||
'defaultsFrom': 'parent',
|
||||
'apiRawValues': 'variables',
|
||||
'run': 'external_program',
|
||||
'args': 'arguments'
|
||||
'args': 'arguments',
|
||||
}
|
||||
|
||||
api_attributes = [
|
||||
'defaultsFrom', 'interval', 'timeout', 'destination', 'run', 'args', 'description'
|
||||
'defaultsFrom', 'interval', 'timeout', 'destination', 'run', 'args',
|
||||
'description',
|
||||
]
|
||||
|
||||
returnables = [
|
||||
'parent', 'ip', 'port', 'interval', 'timeout', 'variables', 'external_program',
|
||||
'arguments', 'description'
|
||||
'arguments', 'description',
|
||||
]
|
||||
|
||||
updatables = [
|
||||
'destination', 'interval', 'timeout', 'variables', 'external_program',
|
||||
'arguments', 'description'
|
||||
'arguments', 'description',
|
||||
]
|
||||
|
||||
def to_return(self):
|
||||
result = {}
|
||||
try:
|
||||
for returnable in self.returnables:
|
||||
result[returnable] = getattr(self, returnable)
|
||||
result = self._filter_params(result)
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
|
||||
@property
|
||||
def destination(self):
|
||||
if self.ip is None and self.port is None:
|
||||
|
@ -285,11 +270,7 @@ class Parameters(AnsibleF5Parameters):
|
|||
def parent(self):
|
||||
if self._values['parent'] is None:
|
||||
return None
|
||||
if self._values['parent'].startswith('/'):
|
||||
parent = os.path.basename(self._values['parent'])
|
||||
result = '/{0}/{1}'.format(self.partition, parent)
|
||||
else:
|
||||
result = '/{0}/{1}'.format(self.partition, self._values['parent'])
|
||||
result = fq_name(self.partition, self._values['parent'])
|
||||
return result
|
||||
|
||||
@property
|
||||
|
@ -426,8 +407,7 @@ class Difference(object):
|
|||
variables=self.want.variables
|
||||
)
|
||||
result = dict()
|
||||
|
||||
different = compare_dictionary([self.want.variables], [self.have.variables])
|
||||
different = compare_dictionary(self.want.variables, self.have.variables)
|
||||
if not different:
|
||||
return None
|
||||
|
||||
|
@ -491,13 +471,10 @@ class ModuleManager(object):
|
|||
result = dict()
|
||||
state = self.want.state
|
||||
|
||||
try:
|
||||
if state == "present":
|
||||
changed = self.present()
|
||||
elif state == "absent":
|
||||
changed = self.absent()
|
||||
except iControlUnexpectedHTTPError as e:
|
||||
raise F5ModuleError(str(e))
|
||||
|
||||
reportable = ReportableChanges(params=self.changes.to_return())
|
||||
changes = reportable.to_return()
|
||||
|
@ -520,19 +497,19 @@ class ModuleManager(object):
|
|||
else:
|
||||
return self.create()
|
||||
|
||||
def create(self):
|
||||
self._set_changed_options()
|
||||
if self.want.timeout is None:
|
||||
self.want.update({'timeout': 16})
|
||||
if self.want.interval is None:
|
||||
self.want.update({'interval': 5})
|
||||
if self.want.ip is None:
|
||||
self.want.update({'ip': '*'})
|
||||
if self.want.port is None:
|
||||
self.want.update({'port': '*'})
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.create_on_device()
|
||||
def exists(self):
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
resp = self.client.api.get(uri)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError:
|
||||
return False
|
||||
if resp.status == 404 or 'code' in response and response['code'] == 404:
|
||||
return False
|
||||
return True
|
||||
|
||||
def update(self):
|
||||
|
@ -544,70 +521,132 @@ class ModuleManager(object):
|
|||
self.update_on_device()
|
||||
return True
|
||||
|
||||
def absent(self):
|
||||
if self.exists():
|
||||
return self.remove()
|
||||
return False
|
||||
|
||||
def remove(self):
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.remove_from_device()
|
||||
if self.exists():
|
||||
raise F5ModuleError("Failed to delete the monitor.")
|
||||
raise F5ModuleError("Failed to delete the resource.")
|
||||
return True
|
||||
|
||||
def read_current_from_device(self):
|
||||
resource = self.client.api.tm.ltm.monitor.externals.external.load(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
)
|
||||
result = resource.attrs
|
||||
return ApiParameters(params=result)
|
||||
def create(self):
|
||||
self._set_changed_options()
|
||||
self._set_default_creation_values()
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.create_on_device()
|
||||
return True
|
||||
|
||||
def exists(self):
|
||||
result = self.client.api.tm.ltm.monitor.externals.external.exists(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
)
|
||||
return result
|
||||
def _set_default_creation_values(self):
|
||||
if self.want.timeout is None:
|
||||
self.want.update({'timeout': 16})
|
||||
if self.want.interval is None:
|
||||
self.want.update({'interval': 5})
|
||||
if self.want.ip is None:
|
||||
self.want.update({'ip': '*'})
|
||||
if self.want.port is None:
|
||||
self.want.update({'port': '*'})
|
||||
|
||||
def update_on_device(self):
|
||||
def create_on_device(self):
|
||||
params = self.changes.api_params()
|
||||
result = self.client.api.tm.ltm.monitor.externals.external.load(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
params['name'] = self.want.name
|
||||
params['partition'] = self.want.partition
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port']
|
||||
)
|
||||
if params:
|
||||
result.modify(**params)
|
||||
if self.changes.variables:
|
||||
self.set_variable_on_device(self.changes.variables)
|
||||
resp = self.client.api.post(uri, json=params)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
|
||||
if 'code' in response and response['code'] in [400, 403]:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
|
||||
if self.want.variables:
|
||||
self.set_variable_on_device(self.want.variables)
|
||||
|
||||
def set_variable_on_device(self, commands):
|
||||
command = ' '.join(['user-defined {0} \\\"{1}\\\"'.format(k, v) for k, v in iteritems(commands)])
|
||||
command = 'tmsh modify ltm monitor external {0} {1}'.format(self.want.name, command)
|
||||
self.client.api.tm.util.bash.exec_cmd(
|
||||
'run',
|
||||
uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
)
|
||||
args = dict(
|
||||
command='run',
|
||||
utilCmdArgs='-c "{0}"'.format(command)
|
||||
)
|
||||
resp = self.client.api.post(uri, json=args)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
if 'code' in response and response['code'] == 400:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
|
||||
def create_on_device(self):
|
||||
params = self.want.api_params()
|
||||
self.client.api.tm.ltm.monitor.externals.external.create(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition,
|
||||
**params
|
||||
def update_on_device(self):
|
||||
params = self.changes.api_params()
|
||||
if params:
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
if self.want.variables:
|
||||
self.set_variable_on_device(self.want.variables)
|
||||
resp = self.client.api.patch(uri, json=params)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
|
||||
if 'code' in response and response['code'] == 400:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
if self.changes.variables:
|
||||
self.set_variable_on_device(self.changes.variables)
|
||||
|
||||
def absent(self):
|
||||
if self.exists():
|
||||
return self.remove()
|
||||
return False
|
||||
|
||||
def remove_from_device(self):
|
||||
result = self.client.api.tm.ltm.monitor.externals.external.load(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
if result:
|
||||
result.delete()
|
||||
resp = self.client.api.delete(uri)
|
||||
if resp.status == 200:
|
||||
return True
|
||||
|
||||
def read_current_from_device(self):
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
resp = self.client.api.get(uri)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
|
||||
if 'code' in response and response['code'] == 400:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
return ApiParameters(params=response)
|
||||
|
||||
|
||||
class ArgumentSpec(object):
|
||||
|
@ -643,20 +682,19 @@ def main():
|
|||
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
client = F5RestClient(**module.params)
|
||||
|
||||
try:
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
module.exit_json(**results)
|
||||
exit_json(module, results, client)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
module.fail_json(msg=str(ex))
|
||||
fail_json(module, ex, client)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -478,12 +478,6 @@ class ModuleManager(object):
|
|||
self.update_on_device()
|
||||
return True
|
||||
|
||||
def should_update(self):
|
||||
result = self._update_changed_options()
|
||||
if result:
|
||||
return True
|
||||
return False
|
||||
|
||||
def remove(self):
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
|
|
|
@ -155,69 +155,57 @@ time_until_up:
|
|||
sample: 2
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
|
||||
try:
|
||||
from library.module_utils.network.f5.bigip import HAS_F5SDK
|
||||
from library.module_utils.network.f5.bigip import F5Client
|
||||
from library.module_utils.network.f5.bigip import F5RestClient
|
||||
from library.module_utils.network.f5.common import F5ModuleError
|
||||
from library.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from library.module_utils.network.f5.common import cleanup_tokens
|
||||
from library.module_utils.network.f5.common import fq_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
from library.module_utils.network.f5.common import transform_name
|
||||
from library.module_utils.network.f5.common import exit_json
|
||||
from library.module_utils.network.f5.common import fail_json
|
||||
from library.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
except ImportError:
|
||||
from ansible.module_utils.network.f5.bigip import HAS_F5SDK
|
||||
from ansible.module_utils.network.f5.bigip import F5Client
|
||||
from ansible.module_utils.network.f5.bigip import F5RestClient
|
||||
from ansible.module_utils.network.f5.common import F5ModuleError
|
||||
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from ansible.module_utils.network.f5.common import cleanup_tokens
|
||||
from ansible.module_utils.network.f5.common import fq_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
from ansible.module_utils.network.f5.common import transform_name
|
||||
from ansible.module_utils.network.f5.common import exit_json
|
||||
from ansible.module_utils.network.f5.common import fail_json
|
||||
from ansible.module_utils.network.f5.ipaddress import is_valid_ip
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
api_map = {
|
||||
'timeUntilUp': 'time_until_up',
|
||||
'defaultsFrom': 'parent',
|
||||
'recv': 'receive'
|
||||
'recv': 'receive',
|
||||
}
|
||||
|
||||
api_attributes = [
|
||||
'timeUntilUp', 'defaultsFrom', 'interval', 'timeout', 'recv', 'send',
|
||||
'destination', 'description'
|
||||
'destination', 'description',
|
||||
]
|
||||
|
||||
returnables = [
|
||||
'parent', 'send', 'receive', 'ip', 'port', 'interval', 'timeout',
|
||||
'time_until_up', 'description'
|
||||
'time_until_up', 'description',
|
||||
]
|
||||
|
||||
updatables = [
|
||||
'destination', 'send', 'receive', 'interval', 'timeout', 'time_until_up',
|
||||
'description'
|
||||
'description',
|
||||
]
|
||||
|
||||
def to_return(self):
|
||||
result = {}
|
||||
try:
|
||||
for returnable in self.returnables:
|
||||
result[returnable] = getattr(self, returnable)
|
||||
result = self._filter_params(result)
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
|
||||
@property
|
||||
def destination(self):
|
||||
if self.ip is None and self.port is None:
|
||||
|
@ -281,11 +269,7 @@ class Parameters(AnsibleF5Parameters):
|
|||
def parent(self):
|
||||
if self._values['parent'] is None:
|
||||
return None
|
||||
if self._values['parent'].startswith('/'):
|
||||
parent = os.path.basename(self._values['parent'])
|
||||
result = '/{0}/{1}'.format(self.partition, parent)
|
||||
else:
|
||||
result = '/{0}/{1}'.format(self.partition, self._values['parent'])
|
||||
result = fq_name(self.partition, self._values['parent'])
|
||||
return result
|
||||
|
||||
@property
|
||||
|
@ -293,7 +277,31 @@ class Parameters(AnsibleF5Parameters):
|
|||
return 'udp'
|
||||
|
||||
|
||||
class ApiParameters(Parameters):
|
||||
pass
|
||||
|
||||
|
||||
class ModuleParameters(Parameters):
|
||||
pass
|
||||
|
||||
|
||||
class Changes(Parameters):
|
||||
def to_return(self):
|
||||
result = {}
|
||||
try:
|
||||
for returnable in self.returnables:
|
||||
result[returnable] = getattr(self, returnable)
|
||||
result = self._filter_params(result)
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
|
||||
|
||||
class UsableChanges(Changes):
|
||||
pass
|
||||
|
||||
|
||||
class ReportableChanges(Changes):
|
||||
pass
|
||||
|
||||
|
||||
|
@ -368,9 +376,9 @@ class ModuleManager(object):
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.have = None
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Changes()
|
||||
self.want = ModuleParameters(params=self.module.params)
|
||||
self.have = ApiParameters()
|
||||
self.changes = UsableChanges()
|
||||
|
||||
def _set_changed_options(self):
|
||||
changed = {}
|
||||
|
@ -378,7 +386,7 @@ class ModuleManager(object):
|
|||
if getattr(self.want, key) is not None:
|
||||
changed[key] = getattr(self.want, key)
|
||||
if changed:
|
||||
self.changes = Changes(params=changed)
|
||||
self.changes = UsableChanges(params=changed)
|
||||
|
||||
def _update_changed_options(self):
|
||||
diff = Difference(self.want, self.have)
|
||||
|
@ -394,7 +402,7 @@ class ModuleManager(object):
|
|||
else:
|
||||
changed[k] = change
|
||||
if changed:
|
||||
self.changes = Changes(params=changed)
|
||||
self.changes = UsableChanges(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -409,15 +417,13 @@ class ModuleManager(object):
|
|||
result = dict()
|
||||
state = self.want.state
|
||||
|
||||
try:
|
||||
if state == "present":
|
||||
changed = self.present()
|
||||
elif state == "absent":
|
||||
changed = self.absent()
|
||||
except iControlUnexpectedHTTPError as e:
|
||||
raise F5ModuleError(str(e))
|
||||
|
||||
changes = self.changes.to_return()
|
||||
reportable = ReportableChanges(params=self.changes.to_return())
|
||||
changes = reportable.to_return()
|
||||
result.update(**changes)
|
||||
result.update(dict(changed=changed))
|
||||
self._announce_deprecations(result)
|
||||
|
@ -426,7 +432,7 @@ class ModuleManager(object):
|
|||
def _announce_deprecations(self, result):
|
||||
warnings = result.pop('__warnings', [])
|
||||
for warning in warnings:
|
||||
self.module.deprecate(
|
||||
self.client.module.deprecate(
|
||||
msg=warning['msg'],
|
||||
version=warning['version']
|
||||
)
|
||||
|
@ -437,31 +443,20 @@ class ModuleManager(object):
|
|||
else:
|
||||
return self.create()
|
||||
|
||||
def create(self):
|
||||
self._set_changed_options()
|
||||
if self.want.timeout is None:
|
||||
self.want.update({'timeout': 16})
|
||||
if self.want.interval is None:
|
||||
self.want.update({'interval': 5})
|
||||
if self.want.time_until_up is None:
|
||||
self.want.update({'time_until_up': 0})
|
||||
if self.want.ip is None:
|
||||
self.want.update({'ip': '*'})
|
||||
if self.want.port is None:
|
||||
self.want.update({'port': '*'})
|
||||
if self.want.send is None:
|
||||
self.want.update({'send': 'default send string'})
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.create_on_device()
|
||||
return True
|
||||
|
||||
def exists(self):
|
||||
result = self.client.api.tm.ltm.monitor.udps.udp.exists(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
return result
|
||||
resp = self.client.api.get(uri)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError:
|
||||
return False
|
||||
if resp.status == 404 or 'code' in response and response['code'] == 404:
|
||||
return False
|
||||
return True
|
||||
|
||||
def update(self):
|
||||
self.have = self.read_current_from_device()
|
||||
|
@ -480,21 +475,66 @@ class ModuleManager(object):
|
|||
raise F5ModuleError("Failed to delete the resource.")
|
||||
return True
|
||||
|
||||
def create(self):
|
||||
self._set_changed_options()
|
||||
self._set_default_creation_values()
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.create_on_device()
|
||||
return True
|
||||
|
||||
def _set_default_creation_values(self):
|
||||
if self.want.timeout is None:
|
||||
self.want.update({'timeout': 16})
|
||||
if self.want.interval is None:
|
||||
self.want.update({'interval': 5})
|
||||
if self.want.time_until_up is None:
|
||||
self.want.update({'time_until_up': 0})
|
||||
if self.want.ip is None:
|
||||
self.want.update({'ip': '*'})
|
||||
if self.want.port is None:
|
||||
self.want.update({'port': '*'})
|
||||
if self.want.send is None:
|
||||
self.want.update({'send': 'default send string'})
|
||||
|
||||
def create_on_device(self):
|
||||
params = self.want.api_params()
|
||||
self.client.api.tm.ltm.monitor.udps.udp.create(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition,
|
||||
**params
|
||||
params = self.changes.api_params()
|
||||
params['name'] = self.want.name
|
||||
params['partition'] = self.want.partition
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port']
|
||||
)
|
||||
resp = self.client.api.post(uri, json=params)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
|
||||
if 'code' in response and response['code'] in [400, 403]:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
|
||||
def update_on_device(self):
|
||||
params = self.want.api_params()
|
||||
resource = self.client.api.tm.ltm.monitor.udps.udp.load(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
params = self.changes.api_params()
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
resource.modify(**params)
|
||||
resp = self.client.api.patch(uri, json=params)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
|
||||
if 'code' in response and response['code'] == 400:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
|
||||
def absent(self):
|
||||
if self.exists():
|
||||
|
@ -502,20 +542,33 @@ class ModuleManager(object):
|
|||
return False
|
||||
|
||||
def remove_from_device(self):
|
||||
resource = self.client.api.tm.ltm.monitor.udps.udp.load(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
if resource:
|
||||
resource.delete()
|
||||
resp = self.client.api.delete(uri)
|
||||
if resp.status == 200:
|
||||
return True
|
||||
|
||||
def read_current_from_device(self):
|
||||
resource = self.client.api.tm.ltm.monitor.udps.udp.load(
|
||||
name=self.want.name,
|
||||
partition=self.want.partition
|
||||
uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port'],
|
||||
transform_name(self.want.partition, self.want.name)
|
||||
)
|
||||
result = resource.attrs
|
||||
return Parameters(params=result)
|
||||
resp = self.client.api.get(uri)
|
||||
try:
|
||||
response = resp.json()
|
||||
except ValueError as ex:
|
||||
raise F5ModuleError(str(ex))
|
||||
|
||||
if 'code' in response and response['code'] == 400:
|
||||
if 'message' in response:
|
||||
raise F5ModuleError(response['message'])
|
||||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
return ApiParameters(params=response)
|
||||
|
||||
|
||||
class ArgumentSpec(object):
|
||||
|
@ -552,20 +605,19 @@ def main():
|
|||
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
client = F5RestClient(**module.params)
|
||||
|
||||
try:
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
module.exit_json(**results)
|
||||
exit_json(module, results, client)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
module.fail_json(msg=str(ex))
|
||||
fail_json(module, ex, client)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -152,7 +152,7 @@ try:
|
|||
from library.module_utils.network.f5.common import cleanup_tokens
|
||||
from library.module_utils.network.f5.common import fq_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
from library.module_utils.network.f5.common import compare_dictionary
|
||||
from library.module_utils.network.f5.common import compare_complex_list
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
|
@ -165,7 +165,7 @@ except ImportError:
|
|||
from ansible.module_utils.network.f5.common import cleanup_tokens
|
||||
from ansible.module_utils.network.f5.common import fq_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
from ansible.module_utils.network.f5.common import compare_dictionary
|
||||
from ansible.module_utils.network.f5.common import compare_complex_list
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
|
@ -371,7 +371,7 @@ class Difference(object):
|
|||
have = [tuple(x.pop('destination_ports')) for x in self.have.rules if 'destination_ports' in x]
|
||||
if set(want) != set(have):
|
||||
return self.want.rules
|
||||
if compare_dictionary(self.want.rules, self.have.rules):
|
||||
if compare_complex_list(self.want.rules, self.have.rules):
|
||||
return self.want.rules
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue