Adds parameters and removes netaddr dependency (#44654)
several new parameters added to bigip_node and the netaddr dependency has been removed.pull/4420/head
parent
b5d45bdd1a
commit
73c97cb779
|
@ -135,16 +135,33 @@ options:
|
||||||
description:
|
description:
|
||||||
description:
|
description:
|
||||||
- Specifies descriptive text that identifies the node.
|
- Specifies descriptive text that identifies the node.
|
||||||
|
- You can remove a description by either specifying an empty string, or by
|
||||||
|
specifying the special value C(none).
|
||||||
|
connection_limit:
|
||||||
|
description:
|
||||||
|
- Node connection limit. Setting this to 0 disables the limit.
|
||||||
|
version_added: 2.7
|
||||||
|
rate_limit:
|
||||||
|
description:
|
||||||
|
- Node rate limit (connections-per-second). Setting this to 0 disables the limit.
|
||||||
|
version_added: 2.7
|
||||||
|
ratio:
|
||||||
|
description:
|
||||||
|
- Node ratio weight. Valid values range from 1 through 100.
|
||||||
|
- When creating a new node, if this parameter is not specified, the default of
|
||||||
|
C(1) will be used.
|
||||||
|
version_added: 2.7
|
||||||
|
dynamic_ratio:
|
||||||
|
description:
|
||||||
|
- The dynamic ratio number for the node. Used for dynamic ratio load balancing.
|
||||||
|
- When creating a new node, if this parameter is not specified, the default of
|
||||||
|
C(1) will be used.
|
||||||
|
version_added: 2.7
|
||||||
partition:
|
partition:
|
||||||
description:
|
description:
|
||||||
- Device partition to manage resources on.
|
- Device partition to manage resources on.
|
||||||
default: Common
|
default: Common
|
||||||
version_added: 2.5
|
version_added: 2.5
|
||||||
notes:
|
|
||||||
- Requires the netaddr Python package on the host. This is as easy as
|
|
||||||
C(pip install netaddr).
|
|
||||||
requirements:
|
|
||||||
- netaddr
|
|
||||||
extends_documentation_fragment: f5
|
extends_documentation_fragment: f5
|
||||||
author:
|
author:
|
||||||
- Tim Rupp (@caphrim007)
|
- Tim Rupp (@caphrim007)
|
||||||
|
@ -266,44 +283,58 @@ from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
|
||||||
from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
|
from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from library.module_utils.network.f5.bigip import HAS_F5SDK
|
from library.module_utils.network.f5.bigip import F5RestClient
|
||||||
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 F5ModuleError
|
||||||
from library.module_utils.network.f5.common import AnsibleF5Parameters
|
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 cleanup_tokens
|
||||||
from library.module_utils.network.f5.common import fq_name
|
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 f5_argument_spec
|
||||||
try:
|
from library.module_utils.network.f5.common import transform_name
|
||||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
from library.module_utils.network.f5.common import exit_json
|
||||||
except ImportError:
|
from library.module_utils.network.f5.common import fail_json
|
||||||
HAS_F5SDK = False
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from ansible.module_utils.network.f5.bigip import HAS_F5SDK
|
from ansible.module_utils.network.f5.bigip import F5RestClient
|
||||||
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 F5ModuleError
|
||||||
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
|
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 cleanup_tokens
|
||||||
from ansible.module_utils.network.f5.common import fq_name
|
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 f5_argument_spec
|
||||||
try:
|
from ansible.module_utils.network.f5.common import transform_name
|
||||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
from ansible.module_utils.network.f5.common import exit_json
|
||||||
except ImportError:
|
from ansible.module_utils.network.f5.common import fail_json
|
||||||
HAS_F5SDK = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
import netaddr
|
|
||||||
HAS_NETADDR = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_NETADDR = False
|
|
||||||
|
|
||||||
|
|
||||||
class Parameters(AnsibleF5Parameters):
|
class Parameters(AnsibleF5Parameters):
|
||||||
api_map = {
|
api_map = {
|
||||||
'monitor': 'monitors'
|
'monitor': 'monitors',
|
||||||
|
'connectionLimit': 'connection_limit',
|
||||||
|
'rateLimit': 'rate_limit'
|
||||||
}
|
}
|
||||||
|
|
||||||
api_attributes = [
|
api_attributes = [
|
||||||
'monitor', 'description', 'address', 'fqdn',
|
# Leave the ``monitor`` attribute commented out
|
||||||
|
#
|
||||||
|
# This attribute is commented out to prevent it from trying to be
|
||||||
|
# sent to the API during a create or update request. This is because
|
||||||
|
# the field is **broken** and **will not work** if you send some
|
||||||
|
# formats of the monitor to the API.
|
||||||
|
#
|
||||||
|
# Specifically, the m_of_n types will not work because they include
|
||||||
|
# the brace ( ``{`` ) character and the API considers this character
|
||||||
|
# to be invalid.
|
||||||
|
#
|
||||||
|
# Monitors are handled in a special case within the ``update_one_device``
|
||||||
|
# and ``create_one_device`` methods. Refer to them if you need to know
|
||||||
|
# what that special case is.
|
||||||
|
#
|
||||||
|
# 'monitor',
|
||||||
|
|
||||||
|
'description',
|
||||||
|
'address',
|
||||||
|
'fqdn',
|
||||||
|
'ratio',
|
||||||
|
'connectionLimit',
|
||||||
|
'rateLimit',
|
||||||
|
|
||||||
# Used for changing state
|
# Used for changing state
|
||||||
#
|
#
|
||||||
|
@ -318,15 +349,37 @@ class Parameters(AnsibleF5Parameters):
|
||||||
]
|
]
|
||||||
|
|
||||||
returnables = [
|
returnables = [
|
||||||
'monitor_type', 'quorum', 'monitors', 'description', 'fqdn', 'session', 'state',
|
'monitor_type',
|
||||||
'fqdn_auto_populate', 'fqdn_address_type', 'fqdn_up_interval',
|
'quorum',
|
||||||
'fqdn_down_interval', 'fqdn_name'
|
'monitors',
|
||||||
|
'description',
|
||||||
|
'fqdn',
|
||||||
|
'session',
|
||||||
|
'state',
|
||||||
|
'fqdn_auto_populate',
|
||||||
|
'fqdn_address_type',
|
||||||
|
'fqdn_up_interval',
|
||||||
|
'fqdn_down_interval',
|
||||||
|
'fqdn_name',
|
||||||
|
'connection_limit',
|
||||||
|
'ratio',
|
||||||
|
'rate_limit'
|
||||||
]
|
]
|
||||||
|
|
||||||
updatables = [
|
updatables = [
|
||||||
'monitor_type', 'quorum', 'monitors', 'description', 'state',
|
'monitor_type',
|
||||||
'fqdn_up_interval', 'fqdn_down_interval', 'tmName', 'fqdn_auto_populate',
|
'quorum',
|
||||||
'fqdn_address_type'
|
'monitors',
|
||||||
|
'description',
|
||||||
|
'state',
|
||||||
|
'fqdn_up_interval',
|
||||||
|
'fqdn_down_interval',
|
||||||
|
'tmName',
|
||||||
|
'fqdn_auto_populate',
|
||||||
|
'fqdn_address_type',
|
||||||
|
'connection_limit',
|
||||||
|
'ratio',
|
||||||
|
'rate_limit'
|
||||||
]
|
]
|
||||||
|
|
||||||
def to_return(self):
|
def to_return(self):
|
||||||
|
@ -362,42 +415,12 @@ class Parameters(AnsibleF5Parameters):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def quorum(self):
|
def rate_limit(self):
|
||||||
if self.kind == 'tm:ltm:pool:poolstate':
|
if self._values['rate_limit'] is None:
|
||||||
if self._values['monitors'] is None:
|
return None
|
||||||
return None
|
if self._values['rate_limit'] == 'disabled':
|
||||||
pattern = r'min\s+(?P<quorum>\d+)\s+of'
|
return 0
|
||||||
matches = re.search(pattern, self._values['monitors'])
|
return int(self._values['rate_limit'])
|
||||||
if matches:
|
|
||||||
quorum = matches.group('quorum')
|
|
||||||
else:
|
|
||||||
quorum = None
|
|
||||||
else:
|
|
||||||
quorum = self._values['quorum']
|
|
||||||
try:
|
|
||||||
if quorum is None:
|
|
||||||
return None
|
|
||||||
return int(quorum)
|
|
||||||
except ValueError:
|
|
||||||
raise F5ModuleError(
|
|
||||||
"The specified 'quorum' must be an integer."
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def monitor_type(self):
|
|
||||||
if self.kind == 'tm:ltm:node:nodestate':
|
|
||||||
if self._values['monitors'] is None:
|
|
||||||
return None
|
|
||||||
pattern = r'min\s+\d+\s+of'
|
|
||||||
matches = re.search(pattern, self._values['monitors'])
|
|
||||||
if matches:
|
|
||||||
return 'm_of_n'
|
|
||||||
else:
|
|
||||||
return 'and_list'
|
|
||||||
else:
|
|
||||||
if self._values['monitor_type'] is None:
|
|
||||||
return None
|
|
||||||
return self._values['monitor_type']
|
|
||||||
|
|
||||||
|
|
||||||
class Changes(Parameters):
|
class Changes(Parameters):
|
||||||
|
@ -416,6 +439,8 @@ class UsableChanges(Changes):
|
||||||
result['autopopulate'] = self._values['fqdn_auto_populate']
|
result['autopopulate'] = self._values['fqdn_auto_populate']
|
||||||
if self._values['fqdn_name'] is not None:
|
if self._values['fqdn_name'] is not None:
|
||||||
result['tmName'] = self._values['fqdn_name']
|
result['tmName'] = self._values['fqdn_name']
|
||||||
|
if not result:
|
||||||
|
return None
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -424,6 +449,26 @@ class ReportableChanges(Changes):
|
||||||
|
|
||||||
|
|
||||||
class ModuleParameters(Parameters):
|
class ModuleParameters(Parameters):
|
||||||
|
@property
|
||||||
|
def quorum(self):
|
||||||
|
if self._values['quorum'] is None:
|
||||||
|
return None
|
||||||
|
quorum = self._values['quorum']
|
||||||
|
try:
|
||||||
|
if quorum is None:
|
||||||
|
return None
|
||||||
|
return int(quorum)
|
||||||
|
except ValueError:
|
||||||
|
raise F5ModuleError(
|
||||||
|
"The specified 'quorum' must be an integer."
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def monitor_type(self):
|
||||||
|
if self._values['monitor_type'] is None:
|
||||||
|
return None
|
||||||
|
return self._values['monitor_type']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fqdn_up_interval(self):
|
def fqdn_up_interval(self):
|
||||||
if self._values['fqdn_up_interval'] is None:
|
if self._values['fqdn_up_interval'] is None:
|
||||||
|
@ -466,8 +511,46 @@ class ModuleParameters(Parameters):
|
||||||
result['autopopulate'] = 'disabled'
|
result['autopopulate'] = 'disabled'
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
if self._values['description'] is None:
|
||||||
|
return None
|
||||||
|
elif self._values['description'] in ['none', '']:
|
||||||
|
return ''
|
||||||
|
return self._values['description']
|
||||||
|
|
||||||
|
|
||||||
class ApiParameters(Parameters):
|
class ApiParameters(Parameters):
|
||||||
|
@property
|
||||||
|
def quorum(self):
|
||||||
|
if self._values['monitors'] is None:
|
||||||
|
return None
|
||||||
|
pattern = r'min\s+(?P<quorum>\d+)\s+of'
|
||||||
|
matches = re.search(pattern, self._values['monitors'])
|
||||||
|
if matches:
|
||||||
|
quorum = matches.group('quorum')
|
||||||
|
else:
|
||||||
|
quorum = None
|
||||||
|
try:
|
||||||
|
if quorum is None:
|
||||||
|
return None
|
||||||
|
return int(quorum)
|
||||||
|
except ValueError:
|
||||||
|
raise F5ModuleError(
|
||||||
|
"The specified 'quorum' must be an integer."
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def monitor_type(self):
|
||||||
|
if self._values['monitors'] is None:
|
||||||
|
return None
|
||||||
|
pattern = r'min\s+\d+\s+of'
|
||||||
|
matches = re.search(pattern, self._values['monitors'])
|
||||||
|
if matches:
|
||||||
|
return 'm_of_n'
|
||||||
|
else:
|
||||||
|
return 'and_list'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fqdn_up_interval(self):
|
def fqdn_up_interval(self):
|
||||||
if self._values['fqdn'] is None:
|
if self._values['fqdn'] is None:
|
||||||
|
@ -496,6 +579,12 @@ class ApiParameters(Parameters):
|
||||||
if 'autopopulate' in self._values['fqdn']:
|
if 'autopopulate' in self._values['fqdn']:
|
||||||
return str(self._values['fqdn']['autopopulate'])
|
return str(self._values['fqdn']['autopopulate'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
if self._values['description'] in [None, 'none']:
|
||||||
|
return None
|
||||||
|
return self._values['description']
|
||||||
|
|
||||||
|
|
||||||
class Difference(object):
|
class Difference(object):
|
||||||
def __init__(self, want, have=None):
|
def __init__(self, want, have=None):
|
||||||
|
@ -522,9 +611,13 @@ class Difference(object):
|
||||||
def monitor_type(self):
|
def monitor_type(self):
|
||||||
if self.want.monitor_type is None:
|
if self.want.monitor_type is None:
|
||||||
self.want.update(dict(monitor_type=self.have.monitor_type))
|
self.want.update(dict(monitor_type=self.have.monitor_type))
|
||||||
|
|
||||||
if self.want.quorum is None:
|
if self.want.quorum is None:
|
||||||
self.want.update(dict(quorum=self.have.quorum))
|
self.want.update(dict(quorum=self.have.quorum))
|
||||||
|
|
||||||
if self.want.monitor_type == 'm_of_n' and self.want.quorum is None:
|
if self.want.monitor_type == 'm_of_n' and self.want.quorum is None:
|
||||||
|
if self.want.quorum is None and self.have.quorum is None:
|
||||||
|
return None
|
||||||
raise F5ModuleError(
|
raise F5ModuleError(
|
||||||
"Quorum value must be specified with monitor_type 'm_of_n'."
|
"Quorum value must be specified with monitor_type 'm_of_n'."
|
||||||
)
|
)
|
||||||
|
@ -608,6 +701,15 @@ class Difference(object):
|
||||||
def fqdn(self):
|
def fqdn(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
if self.want.description is None:
|
||||||
|
return None
|
||||||
|
if self.have.description is None and self.want.description == '':
|
||||||
|
return None
|
||||||
|
if self.want.description != self.have.description:
|
||||||
|
return self.want.description
|
||||||
|
|
||||||
|
|
||||||
class ModuleManager(object):
|
class ModuleManager(object):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -736,6 +838,10 @@ class ModuleManager(object):
|
||||||
self.want.update({'fqdn_up_interval': 3600})
|
self.want.update({'fqdn_up_interval': 3600})
|
||||||
if self.want.fqdn_down_interval is None:
|
if self.want.fqdn_down_interval is None:
|
||||||
self.want.update({'fqdn_down_interval': 5})
|
self.want.update({'fqdn_down_interval': 5})
|
||||||
|
if self.want.ratio is None:
|
||||||
|
self.want.update({'ratio': 1})
|
||||||
|
if self.want.dynamic_ratio is None:
|
||||||
|
self.want.update({'dynamic_ratio': 1})
|
||||||
|
|
||||||
self._set_changed_options()
|
self._set_changed_options()
|
||||||
if self.module.check_mode:
|
if self.module.check_mode:
|
||||||
|
@ -782,63 +888,164 @@ class ModuleManager(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def read_current_from_device(self):
|
def read_current_from_device(self):
|
||||||
resource = self.client.api.tm.ltm.nodes.node.load(
|
uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
|
||||||
name=self.want.name,
|
self.client.provider['server'],
|
||||||
partition=self.want.partition
|
self.client.provider['server_port'],
|
||||||
|
transform_name(self.want.partition, self.want.name)
|
||||||
)
|
)
|
||||||
result = resource.attrs
|
resp = self.client.api.get(uri)
|
||||||
return ApiParameters(params=result)
|
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)
|
||||||
|
|
||||||
def exists(self):
|
def exists(self):
|
||||||
result = self.client.api.tm.ltm.nodes.node.exists(
|
uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
|
||||||
name=self.want.name,
|
self.client.provider['server'],
|
||||||
partition=self.want.partition
|
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_node_offline_on_device(self):
|
def update_node_offline_on_device(self):
|
||||||
params = dict(
|
params = dict(
|
||||||
session="user-disabled",
|
session="user-disabled",
|
||||||
state="user-down"
|
state="user-down"
|
||||||
)
|
)
|
||||||
result = self.client.api.tm.ltm.nodes.node.load(
|
uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
|
||||||
name=self.want.name,
|
self.client.provider['server'],
|
||||||
partition=self.want.partition
|
self.client.provider['server_port'],
|
||||||
|
transform_name(self.want.partition, self.want.name)
|
||||||
)
|
)
|
||||||
result.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 update_on_device(self):
|
def update_on_device(self):
|
||||||
params = self.changes.api_params()
|
params = self.changes.api_params()
|
||||||
result = self.client.api.tm.ltm.nodes.node.load(
|
uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
|
||||||
name=self.want.name,
|
self.client.provider['server'],
|
||||||
partition=self.want.partition
|
self.client.provider['server_port'],
|
||||||
|
transform_name(self.want.partition, self.want.name)
|
||||||
)
|
)
|
||||||
result.modify(**params)
|
if 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)
|
||||||
|
if self.want.monitors:
|
||||||
|
self.update_monitors_on_device()
|
||||||
|
|
||||||
def create_on_device(self):
|
def create_on_device(self):
|
||||||
params = self.want.api_params()
|
params = self.want.api_params()
|
||||||
resource = self.client.api.tm.ltm.nodes.node.create(
|
|
||||||
name=self.want.name,
|
|
||||||
partition=self.want.partition,
|
|
||||||
**params
|
|
||||||
)
|
|
||||||
self._wait_for_fqdn_checks(resource)
|
|
||||||
|
|
||||||
def _wait_for_fqdn_checks(self, resource):
|
params['name'] = self.want.name
|
||||||
|
params['partition'] = self.want.partition
|
||||||
|
uri = "https://{0}:{1}/mgmt/tm/ltm/node/".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)
|
||||||
|
if self.want.monitors:
|
||||||
|
self.update_monitors_on_device()
|
||||||
|
self._wait_for_fqdn_checks()
|
||||||
|
|
||||||
|
def _wait_for_fqdn_checks(self):
|
||||||
while True:
|
while True:
|
||||||
if resource.state == 'fqdn-checking':
|
have = self.read_current_from_device()
|
||||||
resource.refresh()
|
if have.state == 'fqdn-checking':
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
def remove_from_device(self):
|
def remove_from_device(self):
|
||||||
result = self.client.api.tm.ltm.nodes.node.load(
|
uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
|
||||||
name=self.want.name,
|
self.client.provider['server'],
|
||||||
partition=self.want.partition
|
self.client.provider['server_port'],
|
||||||
|
transform_name(self.want.partition, self.want.name)
|
||||||
)
|
)
|
||||||
if result:
|
resp = self.client.api.delete(uri)
|
||||||
result.delete()
|
if resp.status == 200:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def update_monitors_on_device(self):
|
||||||
|
"""Updates the monitors string
|
||||||
|
|
||||||
|
There is a long-standing bug in where the monitor value
|
||||||
|
is a string that includes braces. These braces cause the REST API to panic and
|
||||||
|
fail to update or create any resources that have an "at_least" or "require"
|
||||||
|
set of availability_requirements.
|
||||||
|
|
||||||
|
This method exists to do a tmsh command to cause the update to take place on
|
||||||
|
the device.
|
||||||
|
|
||||||
|
Preferably, this method can be removed and the bug be fixed. The API should
|
||||||
|
be working, obviously, but the more concerning issue is if tmsh commands change
|
||||||
|
over time, breaking this method.
|
||||||
|
"""
|
||||||
|
command = 'tmsh modify ltm node /{0}/{1} monitor {2}'.format(
|
||||||
|
self.want.partition, self.want.name, self.want.monitors
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
"command": "run",
|
||||||
|
"utilCmdArgs": '-c "{0}"'.format(command)
|
||||||
|
}
|
||||||
|
uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
|
||||||
|
self.client.provider['server'],
|
||||||
|
self.client.provider['server_port']
|
||||||
|
)
|
||||||
|
resp = self.client.api.post(uri, json=params)
|
||||||
|
try:
|
||||||
|
response = resp.json()
|
||||||
|
if 'commandResult' in response and len(response['commandResult'].strip()) > 0:
|
||||||
|
raise F5ModuleError(response['commandResult'])
|
||||||
|
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)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ArgumentSpec(object):
|
class ArgumentSpec(object):
|
||||||
|
@ -873,7 +1080,11 @@ class ArgumentSpec(object):
|
||||||
),
|
),
|
||||||
fqdn_auto_populate=dict(type='bool'),
|
fqdn_auto_populate=dict(type='bool'),
|
||||||
fqdn_up_interval=dict(),
|
fqdn_up_interval=dict(),
|
||||||
fqdn_down_interval=dict(type='int')
|
fqdn_down_interval=dict(type='int'),
|
||||||
|
connection_limit=dict(type='int'),
|
||||||
|
rate_limit=dict(type='int'),
|
||||||
|
ratio=dict(type='int'),
|
||||||
|
dynamic_ratio=dict(type='int')
|
||||||
)
|
)
|
||||||
self.argument_spec = {}
|
self.argument_spec = {}
|
||||||
self.argument_spec.update(f5_argument_spec)
|
self.argument_spec.update(f5_argument_spec)
|
||||||
|
@ -885,22 +1096,16 @@ def main():
|
||||||
|
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=spec.argument_spec,
|
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")
|
|
||||||
if not HAS_NETADDR:
|
|
||||||
module.fail_json(msg="The python netaddr module is required")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = F5Client(**module.params)
|
client = F5RestClient(**module.params)
|
||||||
mm = ModuleManager(module=module, client=client)
|
mm = ModuleManager(module=module, client=client)
|
||||||
results = mm.exec_module()
|
results = mm.exec_module()
|
||||||
cleanup_tokens(client)
|
exit_json(module, results, client)
|
||||||
module.exit_json(**results)
|
|
||||||
except F5ModuleError as ex:
|
except F5ModuleError as ex:
|
||||||
cleanup_tokens(client)
|
fail_json(module, ex, client)
|
||||||
module.fail_json(msg=str(ex))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in New Issue