mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-23 05:10:22 -07:00
Various fixes (#34815)
This patch was primarily an effort to reduce traceback errors for work that sivel was doing. Part of (and in some cases in addition to) that, the following was done. * Removed re-def of cleanup_tokens. * Changed parameter args to be keywords. * Changed imports to include new module_util locations. * Imports also include developing (sideband) module_util locations. * Changed to using F5Client and plain AnsibleModule to prevent tracebacks caused by missing libraries. * Removed init and update methods from most Parameter classes (optimization) as its now included in module_utils. * Changed module and module param references to take into account the new self.module arg. * Minor bug fixes made during this refactor.
This commit is contained in:
parent
18d33eeb89
commit
44a5b3abb4
22 changed files with 838 additions and 998 deletions
|
@ -98,8 +98,6 @@ options:
|
|||
- Device partition to manage resources on.
|
||||
default: Common
|
||||
extends_documentation_fragment: f5
|
||||
requirements:
|
||||
- f5-sdk >= 3.0.4
|
||||
author:
|
||||
- Wojciech Wypior (@wojtek0806)
|
||||
- Tim Rupp (@caphrim007)
|
||||
|
@ -219,50 +217,42 @@ name:
|
|||
import os
|
||||
import time
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
from ansible.module_utils.six import iteritems
|
||||
from collections import defaultdict
|
||||
from distutils.version import LooseVersion
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
def __init__(self, params=None):
|
||||
self._values = defaultdict(lambda: None)
|
||||
if params:
|
||||
self.update(params=params)
|
||||
|
||||
def update(self, params=None):
|
||||
if params:
|
||||
for k, v in iteritems(params):
|
||||
if self.api_map is not None and k in self.api_map:
|
||||
map_key = self.api_map[k]
|
||||
else:
|
||||
map_key = k
|
||||
|
||||
# Handle weird API parameters like `dns.proxy.__iter__` by
|
||||
# using a map provided by the module developer
|
||||
class_attr = getattr(type(self), map_key, None)
|
||||
if isinstance(class_attr, property):
|
||||
# There is a mapped value for the api_map key
|
||||
if class_attr.fset is None:
|
||||
# If the mapped value does not have
|
||||
# an associated setter
|
||||
self._values[map_key] = v
|
||||
else:
|
||||
# The mapped value has a setter
|
||||
setattr(self, map_key, v)
|
||||
else:
|
||||
# If the mapped value is not a @property
|
||||
self._values[map_key] = v
|
||||
|
||||
updatables = [
|
||||
'active'
|
||||
]
|
||||
|
@ -290,17 +280,12 @@ class Parameters(AnsibleF5Parameters):
|
|||
|
||||
@property
|
||||
def full_path(self):
|
||||
return self._fqdn_name(self.name)
|
||||
return fqdn_name(self.name)
|
||||
|
||||
def _templates_from_device(self):
|
||||
collection = self.client.api.tm.asm.policy_templates_s.get_collection()
|
||||
return collection
|
||||
|
||||
def _fqdn_name(self, value):
|
||||
if value is not None and not value.startswith('/'):
|
||||
return '/{0}/{1}'.format(self.partition, value)
|
||||
return value
|
||||
|
||||
def to_return(self):
|
||||
result = {}
|
||||
for returnable in self.returnables:
|
||||
|
@ -308,16 +293,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self, self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
|
||||
class V1Parameters(Parameters):
|
||||
@property
|
||||
|
@ -483,8 +458,9 @@ class Difference(object):
|
|||
|
||||
|
||||
class BaseManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.client = kwargs.get('client', None)
|
||||
self.module = kwargs.get('module', None)
|
||||
self.have = None
|
||||
self.changes = Changes()
|
||||
|
||||
|
@ -512,7 +488,7 @@ class BaseManager(object):
|
|||
if getattr(self.want, key) is not None:
|
||||
changed[key] = getattr(self.want, key)
|
||||
if changed:
|
||||
self.changes = Changes(changed)
|
||||
self.changes = Changes(params=changed)
|
||||
|
||||
def should_update(self):
|
||||
result = self._update_changed_options()
|
||||
|
@ -534,7 +510,7 @@ class BaseManager(object):
|
|||
else:
|
||||
changed[k] = change
|
||||
if changed:
|
||||
self.changes = Changes(changed)
|
||||
self.changes = Changes(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -554,9 +530,12 @@ class BaseManager(object):
|
|||
policies = self.client.api.tm.asm.policies_s.get_collection()
|
||||
if any(p.name == self.want.name and p.partition == self.want.partition for p in policies):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _file_is_missing(self):
|
||||
if self.want.template and self.want.file is None:
|
||||
return False
|
||||
if not os.path.exists(self.want.file):
|
||||
return True
|
||||
return False
|
||||
|
@ -570,7 +549,7 @@ class BaseManager(object):
|
|||
"The specified ASM policy file does not exist"
|
||||
)
|
||||
self._set_changed_options()
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
|
||||
if self.want.template is None and self.want.file is None:
|
||||
|
@ -595,7 +574,7 @@ class BaseManager(object):
|
|||
self.have = self.read_current_from_device()
|
||||
if not self.should_update():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.update_on_device()
|
||||
if self.changes.active:
|
||||
|
@ -641,7 +620,7 @@ class BaseManager(object):
|
|||
)
|
||||
|
||||
def remove(self):
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.remove_from_device()
|
||||
if self.exists():
|
||||
|
@ -662,7 +641,7 @@ class BaseManager(object):
|
|||
if policy.name == self.want.name and policy.partition == self.want.partition:
|
||||
params = policy.attrs
|
||||
params.update(dict(self_link=policy.selfLink))
|
||||
return Parameters(params)
|
||||
return Parameters(params=params)
|
||||
raise F5ModuleError("The policy was not found")
|
||||
|
||||
def import_to_device(self):
|
||||
|
@ -710,8 +689,9 @@ class BaseManager(object):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.client = kwargs.get('client', None)
|
||||
self.kwargs = kwargs
|
||||
|
||||
def exec_module(self):
|
||||
if self.version_is_less_than_13():
|
||||
|
@ -722,9 +702,9 @@ class ModuleManager(object):
|
|||
|
||||
def get_manager(self, type):
|
||||
if type == 'v1':
|
||||
return V1Manager(self.client)
|
||||
return V1Manager(**self.kwargs)
|
||||
elif type == 'v2':
|
||||
return V2Manager(self.client)
|
||||
return V2Manager(**self.kwargs)
|
||||
|
||||
def version_is_less_than_13(self):
|
||||
version = self.client.api.tmos_version
|
||||
|
@ -735,19 +715,19 @@ class ModuleManager(object):
|
|||
|
||||
|
||||
class V1Manager(BaseManager):
|
||||
def __init__(self, client):
|
||||
super(V1Manager, self).__init__(client)
|
||||
self.want = V1Parameters()
|
||||
self.want.client = self.client
|
||||
self.want.update(self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
client = kwargs.get('client', None)
|
||||
module = kwargs.get('module', None)
|
||||
super(V1Manager, self).__init__(client=client, module=module)
|
||||
self.want = V1Parameters(params=module.params, client=client)
|
||||
|
||||
|
||||
class V2Manager(BaseManager):
|
||||
def __init__(self, client):
|
||||
super(V2Manager, self).__init__(client)
|
||||
self.want = V2Parameters()
|
||||
self.want.client = self.client
|
||||
self.want.update(self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
client = kwargs.get('client', None)
|
||||
module = kwargs.get('module', None)
|
||||
super(V2Manager, self).__init__(client=client, module=module)
|
||||
self.want = V2Parameters(params=module.params, client=client)
|
||||
|
||||
|
||||
class ArgumentSpec(object):
|
||||
|
@ -790,7 +770,7 @@ class ArgumentSpec(object):
|
|||
'Wordpress',
|
||||
]
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
name=dict(
|
||||
required=True,
|
||||
),
|
||||
|
@ -800,44 +780,43 @@ class ArgumentSpec(object):
|
|||
),
|
||||
active=dict(
|
||||
type='bool'
|
||||
),
|
||||
state=dict(
|
||||
default='present',
|
||||
choices=['present', 'absent']
|
||||
),
|
||||
partition=dict(
|
||||
default='Common',
|
||||
fallback=(env_fallback, ['F5_PARTITION'])
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name,
|
||||
mutually_exclusive=[
|
||||
['file', 'template']
|
||||
]
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -162,66 +162,55 @@ failed_conditions:
|
|||
import re
|
||||
import time
|
||||
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import run_commands
|
||||
HAS_CLI_TRANSPORT = True
|
||||
except ImportError:
|
||||
HAS_CLI_TRANSPORT = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.network.common.parsing import FailedConditionsError
|
||||
from ansible.module_utils.network.common.parsing import Conditional
|
||||
from ansible.module_utils.network.common.utils import ComplexList
|
||||
from ansible.module_utils.network.common.utils import to_list
|
||||
from ansible.module_utils.six import iteritems
|
||||
from collections import defaultdict
|
||||
from collections import deque
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
returnables = ['stdout', 'stdout_lines', 'warnings']
|
||||
|
||||
def __init__(self, params=None):
|
||||
self._values = defaultdict(lambda: None)
|
||||
self._values['__warnings'] = []
|
||||
if params:
|
||||
self.update(params=params)
|
||||
|
||||
def update(self, params=None):
|
||||
if params:
|
||||
for k, v in iteritems(params):
|
||||
if self.api_map is not None and k in self.api_map:
|
||||
map_key = self.api_map[k]
|
||||
else:
|
||||
map_key = k
|
||||
|
||||
# Handle weird API parameters like `dns.proxy.__iter__` by
|
||||
# using a map provided by the module developer
|
||||
class_attr = getattr(type(self), map_key, None)
|
||||
if isinstance(class_attr, property):
|
||||
# There is a mapped value for the api_map key
|
||||
if class_attr.fset is None:
|
||||
# If the mapped value does not have
|
||||
# an associated setter
|
||||
self._values[map_key] = v
|
||||
else:
|
||||
# The mapped value has a setter
|
||||
setattr(self, map_key, v)
|
||||
else:
|
||||
# If the mapped value is not a @property
|
||||
self._values[map_key] = v
|
||||
|
||||
def to_return(self):
|
||||
result = {}
|
||||
for returnable in self.returnables:
|
||||
|
@ -260,9 +249,10 @@ class Parameters(AnsibleF5Parameters):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.want = Parameters(self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def _to_lines(self, stdout):
|
||||
|
@ -278,7 +268,7 @@ class ModuleManager(object):
|
|||
'list', 'show',
|
||||
'modify cli preference pager disabled'
|
||||
]
|
||||
if self.client.module.params['transport'] != 'cli':
|
||||
if self.module.params['transport'] != 'cli':
|
||||
valid_configs = list(map(self.want._ensure_tmsh_prefix, valid_configs))
|
||||
if any(cmd.startswith(x) for x in valid_configs):
|
||||
return True
|
||||
|
@ -308,12 +298,12 @@ class ModuleManager(object):
|
|||
|
||||
conditionals = [Conditional(c) for c in wait_for]
|
||||
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return
|
||||
|
||||
while retries > 0:
|
||||
if self.client.module.params['transport'] == 'cli' and HAS_CLI_TRANSPORT:
|
||||
responses = self._run_commands(self.client.module, commands)
|
||||
if self.module.params['transport'] == 'cli' and HAS_CLI_TRANSPORT:
|
||||
responses = self._run_commands(self.module, commands)
|
||||
else:
|
||||
responses = self.execute_on_device(commands)
|
||||
|
||||
|
@ -334,11 +324,12 @@ class ModuleManager(object):
|
|||
errmsg = 'One or more conditional statements have not been satisfied'
|
||||
raise FailedConditionsError(errmsg, failed_conditions)
|
||||
|
||||
self.changes = Parameters({
|
||||
changes = {
|
||||
'stdout': responses,
|
||||
'stdout_lines': self._to_lines(responses),
|
||||
'warnings': warnings
|
||||
})
|
||||
}
|
||||
self.changes = Parameters(params=changes)
|
||||
if any(x for x in self.want.user_commands if x.startswith(changed)):
|
||||
return True
|
||||
return False
|
||||
|
@ -354,11 +345,11 @@ class ModuleManager(object):
|
|||
),
|
||||
)
|
||||
|
||||
transform = ComplexList(spec, self.client.module)
|
||||
transform = ComplexList(spec, self.module)
|
||||
commands = transform(commands)
|
||||
|
||||
for index, item in enumerate(commands):
|
||||
if not self._is_valid_mode(item['command']) and self.client.module.params['transport'] != 'cli':
|
||||
if not self._is_valid_mode(item['command']) and self.module.params['transport'] != 'cli':
|
||||
warnings.append(
|
||||
'Using "write" commands is not idempotent. You should use '
|
||||
'a module that is specifically made for that. If such a '
|
||||
|
@ -394,7 +385,7 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
commands=dict(
|
||||
type='raw',
|
||||
required=True
|
||||
|
@ -421,44 +412,38 @@ class ArgumentSpec(object):
|
|||
choices=['cli', 'rest']
|
||||
),
|
||||
password=dict(
|
||||
required=False,
|
||||
fallback=(env_fallback, ['F5_PASSWORD']),
|
||||
no_log=True
|
||||
),
|
||||
partition=dict(
|
||||
default='Common',
|
||||
fallback=(env_fallback, ['F5_PARTITION'])
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
|
||||
def main():
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name
|
||||
supports_check_mode=spec.supports_check_mode
|
||||
)
|
||||
|
||||
if client.module.params['transport'] != 'cli' and not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required to use the rest api")
|
||||
if module.params['transport'] != 'cli' and not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required to use the rest api")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -34,18 +34,14 @@ options:
|
|||
no changes are made, the configuration is still saved to the
|
||||
startup config. This option will always cause the module to
|
||||
return changed.
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
type: bool
|
||||
default: no
|
||||
reset:
|
||||
description:
|
||||
- Loads the default configuration on the device. If this option
|
||||
is specified, the default configuration will be loaded before
|
||||
any commands or other provided configuration is run.
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
type: bool
|
||||
default: no
|
||||
merge_content:
|
||||
description:
|
||||
|
@ -59,15 +55,8 @@ options:
|
|||
- Validates the specified configuration to see whether they are
|
||||
valid to replace the running configuration. The running
|
||||
configuration will not be changed.
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
default: yes
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as pip
|
||||
install f5-sdk.
|
||||
requirements:
|
||||
- f5-sdk >= 2.2.3
|
||||
type: bool
|
||||
default: no
|
||||
extends_documentation_fragment: f5
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
|
@ -125,27 +114,42 @@ try:
|
|||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
from ansible.module_utils.six import iteritems
|
||||
from collections import defaultdict
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
returnables = ['stdout', 'stdout_lines']
|
||||
|
||||
def __init__(self, params=None):
|
||||
self._values = defaultdict(lambda: None)
|
||||
if params:
|
||||
self.update(params)
|
||||
|
||||
def to_return(self):
|
||||
result = {}
|
||||
for returnable in self.returnables:
|
||||
|
@ -153,34 +157,12 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
def update(self, params=None):
|
||||
if params:
|
||||
for k, v in iteritems(params):
|
||||
if self.api_map is not None and k in self.api_map:
|
||||
map_key = self.api_map[k]
|
||||
else:
|
||||
map_key = k
|
||||
|
||||
# Handle weird API parameters like `dns.proxy.__iter__` by
|
||||
# using a map provided by the module developer
|
||||
class_attr = getattr(type(self), map_key, None)
|
||||
if isinstance(class_attr, property):
|
||||
# There is a mapped value for the api_map key
|
||||
if class_attr.fset is None:
|
||||
# If the mapped value does not have an associated setter
|
||||
self._values[map_key] = v
|
||||
else:
|
||||
# The mapped value has a setter
|
||||
setattr(self, map_key, v)
|
||||
else:
|
||||
# If the mapped value is not a @property
|
||||
self._values[map_key] = v
|
||||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.want = Parameters(self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def _set_changed_options(self):
|
||||
|
@ -189,7 +171,7 @@ class ModuleManager(object):
|
|||
if getattr(self.want, key) is not None:
|
||||
changed[key] = getattr(self.want, key)
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
|
||||
def _to_lines(self, stdout):
|
||||
lines = list()
|
||||
|
@ -229,13 +211,14 @@ class ModuleManager(object):
|
|||
response = self.save()
|
||||
responses.append(response)
|
||||
|
||||
self.changes = Parameters({
|
||||
changes = {
|
||||
'stdout': responses,
|
||||
'stdout_lines': self._to_lines(responses)
|
||||
})
|
||||
}
|
||||
self.changes = Parameters(params=changes)
|
||||
|
||||
def reset(self):
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
return self.reset_device()
|
||||
|
||||
|
@ -254,7 +237,7 @@ class ModuleManager(object):
|
|||
remote_path = "/var/config/rest/downloads/{0}".format(temp_name)
|
||||
temp_path = '/tmp/' + temp_name
|
||||
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
|
||||
self.upload_to_device(temp_name)
|
||||
|
@ -302,7 +285,7 @@ class ModuleManager(object):
|
|||
upload.upload_stringio(template, temp_name)
|
||||
|
||||
def save(self):
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
return self.save_on_device()
|
||||
|
||||
|
@ -321,7 +304,7 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
reset=dict(
|
||||
type='bool',
|
||||
default=False
|
||||
|
@ -329,46 +312,37 @@ class ArgumentSpec(object):
|
|||
merge_content=dict(),
|
||||
verify=dict(
|
||||
type='bool',
|
||||
default=True
|
||||
default=False
|
||||
),
|
||||
save=dict(
|
||||
type='bool',
|
||||
default=True
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name
|
||||
supports_check_mode=spec.supports_check_mode
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -53,12 +53,8 @@ options:
|
|||
- yes
|
||||
- no
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as pip
|
||||
install f5-sdk.
|
||||
- Requires the objectpath Python package on the host. This is as easy as pip
|
||||
install objectpath.
|
||||
requirements:
|
||||
- f5-sdk >= 2.2.3
|
||||
- Requires the objectpath Python package on the host. This is as easy as
|
||||
C(pip install objectpath).
|
||||
extends_documentation_fragment: f5
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
|
@ -100,8 +96,8 @@ RETURN = r'''
|
|||
# only common fields returned
|
||||
'''
|
||||
|
||||
import time
|
||||
import re
|
||||
import time
|
||||
|
||||
try:
|
||||
from objectpath import Tree
|
||||
|
@ -109,16 +105,38 @@ try:
|
|||
except ImportError:
|
||||
HAS_OBJPATH = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.basic import BOOLEANS_TRUE
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
|
@ -184,9 +202,11 @@ class Parameters(AnsibleF5Parameters):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.want = Parameters(self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def exec_module(self):
|
||||
result = dict()
|
||||
|
@ -319,8 +339,9 @@ class ModuleManager(object):
|
|||
|
||||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
self.supports_check_mode = False
|
||||
|
||||
argument_spec = dict(
|
||||
sync_device_to_group=dict(
|
||||
type='bool'
|
||||
),
|
||||
|
@ -335,7 +356,10 @@ class ArgumentSpec(object):
|
|||
required=True
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
self.required_one_of = [
|
||||
['sync_device_to_group', 'sync_most_recent_to_device']
|
||||
]
|
||||
|
@ -347,45 +371,27 @@ class ArgumentSpec(object):
|
|||
]
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError(
|
||||
"The python 'f5-sdk' module is required. This can be done with 'pip install f5-sdk'"
|
||||
)
|
||||
|
||||
if not HAS_OBJPATH:
|
||||
raise F5ModuleError(
|
||||
"The python 'objectpath' module is required. This can be done with 'pip install objectpath'"
|
||||
)
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
mutually_exclusive=spec.mutually_exclusive,
|
||||
required_one_of=spec.required_one_of,
|
||||
f5_product_name=spec.f5_product_name
|
||||
required_one_of=spec.required_one_of
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
bigip_configsync_action.py
|
|
@ -70,13 +70,9 @@ options:
|
|||
provided, a default of C(62960) will be used. This value must be between
|
||||
0 and 65535.
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as pip
|
||||
install f5-sdk.
|
||||
- This module is primarily used as a component of configuring HA pairs of
|
||||
BIG-IP devices.
|
||||
- Requires BIG-IP >= 12.0.0
|
||||
requirements:
|
||||
- f5-sdk >= 2.2.3
|
||||
extends_documentation_fragment: f5
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
|
@ -142,26 +138,49 @@ multicast_port:
|
|||
sample: 1026
|
||||
'''
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six import iteritems
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
try:
|
||||
from netaddr import IPAddress, AddrFormatError
|
||||
HAS_NETADDR = True
|
||||
except ImportError:
|
||||
HAS_NETADDR = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
api_map = {
|
||||
'unicastAddress': 'unicast_failover',
|
||||
'configsyncIp': 'config_sync_ip',
|
||||
'multicastInterface': 'multicast_interface',
|
||||
'multicastIp': 'multicast_address',
|
||||
|
@ -234,44 +253,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = self._get_validated_ip_address('config_sync_ip')
|
||||
return result
|
||||
|
||||
@property
|
||||
def unicastAddress(self):
|
||||
return self.unicast_failover
|
||||
|
||||
@unicastAddress.setter
|
||||
def unicastAddress(self, value):
|
||||
result = []
|
||||
for item in value:
|
||||
item['address'] = item.pop('ip')
|
||||
result.append(item)
|
||||
if result:
|
||||
self._values['unicast_failover'] = result
|
||||
|
||||
@property
|
||||
def unicast_failover(self):
|
||||
if self._values['unicast_failover'] is None:
|
||||
return None
|
||||
if self._values['unicast_failover'] == ['none']:
|
||||
return []
|
||||
result = []
|
||||
for item in self._values['unicast_failover']:
|
||||
address = item.get('address', None)
|
||||
port = item.get('port', None)
|
||||
address = self._validate_unicast_failover_address(address)
|
||||
port = self._validate_unicast_failover_port(port)
|
||||
result.append(
|
||||
dict(
|
||||
effectiveIp=address,
|
||||
effectivePort=port,
|
||||
ip=address,
|
||||
port=port
|
||||
)
|
||||
)
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
def _validate_unicast_failover_port(self, port):
|
||||
try:
|
||||
result = int(port)
|
||||
|
@ -310,15 +291,36 @@ class Parameters(AnsibleF5Parameters):
|
|||
)
|
||||
)
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self, self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
class ApiParameters(Parameters):
|
||||
pass
|
||||
|
||||
|
||||
class ModuleParameters(Parameters):
|
||||
@property
|
||||
def unicast_failover(self):
|
||||
if self._values['unicast_failover'] is None:
|
||||
return None
|
||||
if self._values['unicast_failover'] == ['none']:
|
||||
return []
|
||||
result = []
|
||||
for item in self._values['unicast_failover']:
|
||||
address = item.get('address', None)
|
||||
port = item.get('port', None)
|
||||
address = self._validate_unicast_failover_address(address)
|
||||
port = self._validate_unicast_failover_port(port)
|
||||
result.append(
|
||||
dict(
|
||||
effectiveIp=address,
|
||||
effectivePort=port,
|
||||
ip=address,
|
||||
port=port
|
||||
)
|
||||
)
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class Changes(Parameters):
|
||||
|
@ -459,9 +461,10 @@ class Difference(object):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.want = Parameters(self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.want = ModuleParameters(params=self.module.params)
|
||||
self.changes = UsableChanges()
|
||||
|
||||
def _update_changed_options(self):
|
||||
|
@ -478,7 +481,7 @@ class ModuleManager(object):
|
|||
else:
|
||||
changed[k] = change
|
||||
if changed:
|
||||
self.changes = UsableChanges(changed)
|
||||
self.changes = UsableChanges(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -499,7 +502,7 @@ class ModuleManager(object):
|
|||
except iControlUnexpectedHTTPError as e:
|
||||
raise F5ModuleError(str(e))
|
||||
|
||||
reportable = ReportableChanges(self.changes.to_return())
|
||||
reportable = ReportableChanges(params=self.changes.to_return())
|
||||
changes = reportable.to_return()
|
||||
result.update(**changes)
|
||||
result.update(dict(changed=changed))
|
||||
|
@ -509,7 +512,7 @@ class ModuleManager(object):
|
|||
self.have = self.read_current_from_device()
|
||||
if not self.should_update():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.update_on_device()
|
||||
return True
|
||||
|
@ -530,7 +533,7 @@ class ModuleManager(object):
|
|||
for resource in collection:
|
||||
if resource.selfDevice == 'true':
|
||||
result = resource.attrs
|
||||
return Parameters(result)
|
||||
return ApiParameters(params=result)
|
||||
raise F5ModuleError(
|
||||
"The host device was not found."
|
||||
)
|
||||
|
@ -539,7 +542,7 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
multicast_port=dict(
|
||||
type='int'
|
||||
),
|
||||
|
@ -559,45 +562,37 @@ class ArgumentSpec(object):
|
|||
choices=['present']
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
self.required_together = [
|
||||
['multicast_address', 'multicast_interface', 'multicast_port']
|
||||
]
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
if not HAS_NETADDR:
|
||||
raise F5ModuleError("The python netaddr module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name
|
||||
required_together=spec.required_together
|
||||
)
|
||||
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:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -55,12 +55,7 @@ options:
|
|||
choices:
|
||||
- absent
|
||||
- present
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as pip
|
||||
install f5-sdk.
|
||||
extends_documentation_fragment: f5
|
||||
requirements:
|
||||
- f5-sdk
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
'''
|
||||
|
@ -109,15 +104,37 @@ warnings:
|
|||
sample: ['...', '...']
|
||||
'''
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
|
@ -151,16 +168,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self, self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
@property
|
||||
def search(self):
|
||||
result = []
|
||||
|
@ -211,10 +218,11 @@ class Parameters(AnsibleF5Parameters):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.have = None
|
||||
self.want = Parameters(self.client.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def _update_changed_options(self):
|
||||
|
@ -226,7 +234,7 @@ class ModuleManager(object):
|
|||
if attr1 != attr2:
|
||||
changed[key] = attr1
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -260,13 +268,13 @@ class ModuleManager(object):
|
|||
if 'include' not in attrs:
|
||||
attrs['include'] = 4
|
||||
result.update(attrs)
|
||||
return Parameters(result)
|
||||
return Parameters(params=result)
|
||||
|
||||
def update(self):
|
||||
self.have = self.read_current_from_device()
|
||||
if not self.should_update():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.update_on_device()
|
||||
return True
|
||||
|
@ -299,7 +307,7 @@ class ModuleManager(object):
|
|||
if set_new != set_have:
|
||||
changed[key] = list(set_new)
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -313,7 +321,7 @@ class ModuleManager(object):
|
|||
self.have = self.read_current_from_device()
|
||||
if not self.should_absent():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.absent_on_device()
|
||||
return True
|
||||
|
@ -327,11 +335,9 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
cache=dict(
|
||||
required=False,
|
||||
choices=['disabled', 'enabled', 'disable', 'enable'],
|
||||
default=None
|
||||
choices=['disabled', 'enabled', 'disable', 'enable']
|
||||
),
|
||||
name_servers=dict(
|
||||
required=False,
|
||||
|
@ -355,48 +361,38 @@ class ArgumentSpec(object):
|
|||
type='int'
|
||||
),
|
||||
state=dict(
|
||||
required=False,
|
||||
default='present',
|
||||
choices=['absent', 'present']
|
||||
)
|
||||
)
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
self.required_one_of = [
|
||||
['name_servers', 'search', 'forwarders', 'ip_version', 'cache']
|
||||
]
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name,
|
||||
required_one_of=spec.required_one_of
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -38,18 +38,18 @@ options:
|
|||
auth_pam_validate_ip:
|
||||
description:
|
||||
- Sets the authPamValidateIp setting.
|
||||
choices: ['on', 'off']
|
||||
type: bool
|
||||
auth_pam_dashboard_timeout:
|
||||
description:
|
||||
- Sets whether or not the BIG-IP dashboard will timeout.
|
||||
choices: ['on', 'off']
|
||||
type: bool
|
||||
fast_cgi_timeout:
|
||||
description:
|
||||
- Sets the timeout of FastCGI.
|
||||
hostname_lookup:
|
||||
description:
|
||||
- Sets whether or not to display the hostname, if possible.
|
||||
choices: ['on', 'off']
|
||||
type: bool
|
||||
log_level:
|
||||
description:
|
||||
- Sets the minimum httpd log level.
|
||||
|
@ -60,17 +60,14 @@ options:
|
|||
redirect_http_to_https:
|
||||
description:
|
||||
- Whether or not to redirect http requests to the GUI to https.
|
||||
choices: ['yes', 'no']
|
||||
type: bool
|
||||
ssl_port:
|
||||
description:
|
||||
- The HTTPS port to listen on.
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as pip
|
||||
install f5-sdk.
|
||||
- Requires the requests Python package on the host. This is as easy as
|
||||
pip install requests.
|
||||
C(pip install requests).
|
||||
requirements:
|
||||
- f5-sdk >= 3.0.4
|
||||
- requests
|
||||
extends_documentation_fragment: f5
|
||||
author:
|
||||
|
@ -159,17 +156,37 @@ ssl_port:
|
|||
|
||||
import time
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
from ansible.module_utils.six import iteritems
|
||||
from collections import defaultdict
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
try:
|
||||
from requests.exceptions import ConnectionError
|
||||
|
@ -212,46 +229,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
'allow'
|
||||
]
|
||||
|
||||
def __init__(self, params=None):
|
||||
self._values = defaultdict(lambda: None)
|
||||
self._values['__warnings'] = []
|
||||
if params:
|
||||
self.update(params=params)
|
||||
|
||||
def update(self, params=None):
|
||||
if params:
|
||||
for k, v in iteritems(params):
|
||||
if self.api_map is not None and k in self.api_map:
|
||||
map_key = self.api_map[k]
|
||||
else:
|
||||
map_key = k
|
||||
|
||||
# Handle weird API parameters like `dns.proxy.__iter__` by
|
||||
# using a map provided by the module developer
|
||||
class_attr = getattr(type(self), map_key, None)
|
||||
if isinstance(class_attr, property):
|
||||
# There is a mapped value for the api_map key
|
||||
if class_attr.fset is None:
|
||||
# If the mapped value does not have
|
||||
# an associated setter
|
||||
self._values[map_key] = v
|
||||
else:
|
||||
# The mapped value has a setter
|
||||
setattr(self, map_key, v)
|
||||
else:
|
||||
# If the mapped value is not a @property
|
||||
self._values[map_key] = v
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self, self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
@property
|
||||
def auth_pam_idle_timeout(self):
|
||||
if self._values['auth_pam_idle_timeout'] is None:
|
||||
|
@ -395,9 +372,10 @@ class Difference(object):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.want = ModuleParameters(params=self.client.module.params)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.want = ModuleParameters(params=self.module.params)
|
||||
self.have = ApiParameters()
|
||||
self.changes = UsableChanges()
|
||||
|
||||
|
@ -407,7 +385,7 @@ class ModuleManager(object):
|
|||
if getattr(self.want, key) is not None:
|
||||
changed[key] = getattr(self.want, key)
|
||||
if changed:
|
||||
self.changes = Changes(changed)
|
||||
self.changes = Changes(params=changed)
|
||||
|
||||
def _update_changed_options(self):
|
||||
diff = Difference(self.want, self.have)
|
||||
|
@ -423,7 +401,7 @@ class ModuleManager(object):
|
|||
else:
|
||||
changed[k] = change
|
||||
if changed:
|
||||
self.changes = UsableChanges(changed)
|
||||
self.changes = UsableChanges(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -441,7 +419,7 @@ class ModuleManager(object):
|
|||
except iControlUnexpectedHTTPError as e:
|
||||
raise F5ModuleError(str(e))
|
||||
|
||||
reportable = ReportableChanges(self.changes.to_return())
|
||||
reportable = ReportableChanges(params=self.changes.to_return())
|
||||
changes = reportable.to_return()
|
||||
result.update(**changes)
|
||||
result.update(dict(changed=changed))
|
||||
|
@ -451,7 +429,7 @@ class ModuleManager(object):
|
|||
def _announce_deprecations(self, result):
|
||||
warnings = result.pop('__warnings', [])
|
||||
for warning in warnings:
|
||||
self.client.module.deprecate(
|
||||
self.module.deprecate(
|
||||
msg=warning['msg'],
|
||||
version=warning['version']
|
||||
)
|
||||
|
@ -463,7 +441,7 @@ class ModuleManager(object):
|
|||
self.have = self.read_current_from_device()
|
||||
if not self.should_update():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.update_on_device()
|
||||
return True
|
||||
|
@ -494,7 +472,7 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
allow=dict(
|
||||
type='list'
|
||||
),
|
||||
|
@ -530,42 +508,32 @@ class ArgumentSpec(object):
|
|||
type='bool'
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
if not HAS_REQUESTS:
|
||||
raise F5ModuleError("The python requests module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name
|
||||
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_REQUESTS:
|
||||
module.fail_json(msg="The python requests module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -37,12 +37,7 @@ options:
|
|||
- The timezone to set for NTP lookups. At least one of C(ntp_servers) or
|
||||
C(timezone) is required.
|
||||
default: UTC
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as pip
|
||||
install f5-sdk.
|
||||
extends_documentation_fragment: f5
|
||||
requirements:
|
||||
- f5-sdk
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
- Wojciech Wypior (@wojtek0806)
|
||||
|
@ -82,16 +77,37 @@ timezone:
|
|||
sample: true
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
|
@ -122,23 +138,13 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self,
|
||||
self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.have = None
|
||||
self.want = Parameters(self.client.module.params)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def _update_changed_options(self):
|
||||
|
@ -150,7 +156,7 @@ class ModuleManager(object):
|
|||
if attr1 != attr2:
|
||||
changed[key] = attr1
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -163,7 +169,7 @@ class ModuleManager(object):
|
|||
if set_want != set_have:
|
||||
changed[key] = list(set_want)
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -189,7 +195,7 @@ class ModuleManager(object):
|
|||
self.have = self.read_current_from_device()
|
||||
if not self.should_update():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.update_on_device()
|
||||
return True
|
||||
|
@ -210,7 +216,7 @@ class ModuleManager(object):
|
|||
self.have = self.read_current_from_device()
|
||||
if not self.should_absent():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.absent_on_device()
|
||||
return True
|
||||
|
@ -223,7 +229,7 @@ class ModuleManager(object):
|
|||
def read_current_from_device(self):
|
||||
resource = self.client.api.tm.sys.ntp.load()
|
||||
result = resource.attrs
|
||||
return Parameters(result)
|
||||
return Parameters(params=result)
|
||||
|
||||
def absent_on_device(self):
|
||||
params = self.changes.api_params()
|
||||
|
@ -234,54 +240,45 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
ntp_servers=dict(
|
||||
required=False,
|
||||
default=None,
|
||||
type='list',
|
||||
),
|
||||
timezone=dict(
|
||||
required=False,
|
||||
default=None,
|
||||
)
|
||||
timezone=dict(),
|
||||
state=dict(
|
||||
default='present',
|
||||
choices=['present', 'absent']
|
||||
),
|
||||
)
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
self.required_one_of = [
|
||||
['ntp_servers', 'timezone']
|
||||
]
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name,
|
||||
required_one_of=spec.required_one_of
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -66,12 +66,8 @@ options:
|
|||
description:
|
||||
- Port that you want the SSH daemon to run on.
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host This is as easy as pip
|
||||
install f5-sdk.
|
||||
- Requires BIG-IP version 12.0.0 or greater
|
||||
extends_documentation_fragment: f5
|
||||
requirements:
|
||||
- f5-sdk
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
'''
|
||||
|
@ -149,16 +145,37 @@ port:
|
|||
sample: 22
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
|
@ -190,16 +207,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self, self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
@property
|
||||
def inactivity_timeout(self):
|
||||
if self._values['inactivity_timeout'] is None:
|
||||
|
@ -223,10 +230,11 @@ class Parameters(AnsibleF5Parameters):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.have = None
|
||||
self.want = Parameters(self.client.module.params)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def _update_changed_options(self):
|
||||
|
@ -238,7 +246,7 @@ class ModuleManager(object):
|
|||
if attr1 != attr2:
|
||||
changed[key] = attr1
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -258,13 +266,13 @@ class ModuleManager(object):
|
|||
def read_current_from_device(self):
|
||||
resource = self.client.api.tm.sys.sshd.load()
|
||||
result = resource.attrs
|
||||
return Parameters(result)
|
||||
return Parameters(params=result)
|
||||
|
||||
def update(self):
|
||||
self.have = self.read_current_from_device()
|
||||
if not self.should_update():
|
||||
return False
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.update_on_device()
|
||||
return True
|
||||
|
@ -289,7 +297,7 @@ class ArgumentSpec(object):
|
|||
'quiet', 'verbose'
|
||||
]
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
allow=dict(
|
||||
type='list'
|
||||
),
|
||||
|
@ -308,45 +316,32 @@ class ArgumentSpec(object):
|
|||
),
|
||||
port=dict(
|
||||
type='int'
|
||||
),
|
||||
state=dict(
|
||||
default='present',
|
||||
choices=['present']
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name
|
||||
supports_check_mode=spec.supports_check_mode
|
||||
)
|
||||
if not HAS_F5SDK:
|
||||
module.fail_json(msg="The python f5-sdk module is required")
|
||||
|
||||
try:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -60,11 +60,15 @@ options:
|
|||
- peer
|
||||
- subordinate
|
||||
default: peer
|
||||
notes:
|
||||
- Requires the f5-sdk Python package on the host. This is as easy as
|
||||
pip install f5-sdk.
|
||||
state:
|
||||
description:
|
||||
- When C(present), ensures the specified devices are trusted.
|
||||
- When C(absent), removes the device trusts.
|
||||
default: present
|
||||
choices:
|
||||
- absent
|
||||
- present
|
||||
requirements:
|
||||
- f5-sdk
|
||||
- netaddr
|
||||
extends_documentation_fragment: f5
|
||||
author:
|
||||
|
@ -101,22 +105,44 @@ peer_hostname:
|
|||
|
||||
import re
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
HAS_DEVEL_IMPORTS = False
|
||||
|
||||
try:
|
||||
# Sideband repository used for dev
|
||||
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 fqdn_name
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
HAS_DEVEL_IMPORTS = True
|
||||
except ImportError:
|
||||
# Upstream Ansible
|
||||
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 fqdn_name
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
try:
|
||||
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
try:
|
||||
import netaddr
|
||||
HAS_NETADDR = True
|
||||
except ImportError:
|
||||
HAS_NETADDR = False
|
||||
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Client
|
||||
from ansible.module_utils.f5_utils import AnsibleF5Parameters
|
||||
from ansible.module_utils.f5_utils import HAS_F5SDK
|
||||
from ansible.module_utils.f5_utils import F5ModuleError
|
||||
|
||||
try:
|
||||
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
|
||||
except ImportError:
|
||||
HAS_F5SDK = False
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
api_map = {
|
||||
|
@ -147,16 +173,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
except Exception:
|
||||
return result
|
||||
|
||||
def api_params(self):
|
||||
result = {}
|
||||
for api_attribute in self.api_attributes:
|
||||
if self.api_map is not None and api_attribute in self.api_map:
|
||||
result[api_attribute] = getattr(self, self.api_map[api_attribute])
|
||||
else:
|
||||
result[api_attribute] = getattr(self, api_attribute)
|
||||
result = self._filter_params(result)
|
||||
return result
|
||||
|
||||
@property
|
||||
def peer_server(self):
|
||||
if self._values['peer_server'] is None:
|
||||
|
@ -177,12 +193,6 @@ class Parameters(AnsibleF5Parameters):
|
|||
result = regex.sub('_', self._values['peer_hostname'])
|
||||
return result
|
||||
|
||||
@property
|
||||
def partition(self):
|
||||
# Partitions are not supported when making peers.
|
||||
# Everybody goes in Common.
|
||||
return None
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
if self._values['type'] == 'peer':
|
||||
|
@ -191,10 +201,11 @@ class Parameters(AnsibleF5Parameters):
|
|||
|
||||
|
||||
class ModuleManager(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.have = None
|
||||
self.want = Parameters(self.client.module.params)
|
||||
self.want = Parameters(params=self.module.params)
|
||||
self.changes = Parameters()
|
||||
|
||||
def _set_changed_options(self):
|
||||
|
@ -203,7 +214,7 @@ class ModuleManager(object):
|
|||
if getattr(self.want, key) is not None:
|
||||
changed[key] = getattr(self.want, key)
|
||||
if changed:
|
||||
self.changes = Parameters(changed)
|
||||
self.changes = Parameters(params=changed)
|
||||
|
||||
def exec_module(self):
|
||||
changed = False
|
||||
|
@ -237,8 +248,9 @@ class ModuleManager(object):
|
|||
self.want.update({'peer_password': self.want.password})
|
||||
if self.want.peer_hostname is None:
|
||||
self.want.update({'peer_hostname': self.want.server})
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
|
||||
self.create_on_device()
|
||||
return True
|
||||
|
||||
|
@ -248,7 +260,7 @@ class ModuleManager(object):
|
|||
return False
|
||||
|
||||
def remove(self):
|
||||
if self.client.check_mode:
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
self.remove_from_device()
|
||||
if self.exists():
|
||||
|
@ -284,7 +296,7 @@ class ModuleManager(object):
|
|||
class ArgumentSpec(object):
|
||||
def __init__(self):
|
||||
self.supports_check_mode = True
|
||||
self.argument_spec = dict(
|
||||
argument_spec = dict(
|
||||
peer_server=dict(required=True),
|
||||
peer_hostname=dict(),
|
||||
peer_user=dict(),
|
||||
|
@ -292,44 +304,38 @@ class ArgumentSpec(object):
|
|||
type=dict(
|
||||
choices=['peer', 'subordinate'],
|
||||
default='peer'
|
||||
),
|
||||
state=dict(
|
||||
default='present',
|
||||
choices=['present', 'absent']
|
||||
)
|
||||
)
|
||||
self.f5_product_name = 'bigip'
|
||||
|
||||
|
||||
def cleanup_tokens(client):
|
||||
try:
|
||||
resource = client.api.shared.authz.tokens_s.token.load(
|
||||
name=client.api.icrs.token
|
||||
)
|
||||
resource.delete()
|
||||
except Exception:
|
||||
pass
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
self.argument_spec.update(argument_spec)
|
||||
|
||||
|
||||
def main():
|
||||
if not HAS_F5SDK:
|
||||
raise F5ModuleError("The python f5-sdk module is required")
|
||||
|
||||
if not HAS_NETADDR:
|
||||
raise F5ModuleError("The python netaddr module is required")
|
||||
|
||||
spec = ArgumentSpec()
|
||||
|
||||
client = AnsibleF5Client(
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
f5_product_name=spec.f5_product_name
|
||||
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:
|
||||
mm = ModuleManager(client)
|
||||
client = F5Client(**module.params)
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
client.module.exit_json(**results)
|
||||
except F5ModuleError as e:
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
client.module.fail_json(msg=str(e))
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue