Adds refactors for more f5 modules (#34824)

The main patch is to remove the traceback generating code. There are
other small fixes that were made in addition to doing that.

* 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.
pull/34830/head
Tim Rupp 7 years ago committed by GitHub
parent 0e4e7de000
commit a10aee0fc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -110,11 +110,9 @@ options:
version_added: 2.5
notes:
- Requires BIG-IP software version >= 12.
- F5 developed module 'F5-SDK' required (https://github.com/F5Networks/f5-common-python).
- Best run as a local_action in your playbook.
requirements:
- f5-sdk
- Python >= 2.7
- To add members do a pool, use the C(bigip_pool_member) module. Previously, the
C(bigip_pool) module allowed the management of users, but this has been removed
in version 2.5 of Ansible.
extends_documentation_fragment: f5
author:
- Tim Rupp (@caphrim007)
@ -297,23 +295,45 @@ metadata:
import re
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.basic import env_fallback
from ansible.module_utils.six import iteritems
from collections import defaultdict
HAS_DEVEL_IMPORTS = False
try:
from netaddr import IPAddress, AddrFormatError
HAS_NETADDR = True
# 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_NETADDR = 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 ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from netaddr import IPAddress, AddrFormatError
HAS_NETADDR = True
except ImportError:
HAS_F5SDK = False
HAS_NETADDR = False
class Parameters(AnsibleF5Parameters):
@ -342,35 +362,6 @@ class Parameters(AnsibleF5Parameters):
'metadata'
]
def __init__(self, params=None):
self._values = defaultdict(lambda: None)
if params:
self.update(params=params)
self._values['__warnings'] = []
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
@property
def lb_method(self):
lb_method = self._values['lb_method']
@ -399,18 +390,6 @@ class Parameters(AnsibleF5Parameters):
result = ' and '.join(monitors).strip()
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
def _verify_quorum_type(self, quorum):
try:
if quorum is None:
@ -650,9 +629,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()
@ -669,7 +649,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))
@ -679,7 +659,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']
)
@ -690,7 +670,7 @@ class ModuleManager(object):
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
def _update_changed_options(self):
diff = Difference(self.want, self.have)
@ -706,7 +686,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
return True
return False
@ -731,13 +711,13 @@ 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
def remove(self):
if self.client.check_mode:
if self.module.check_mode:
return True
self.remove_from_device()
if self.exists():
@ -764,7 +744,7 @@ class ModuleManager(object):
)
self._set_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
self.create_on_device()
return True
@ -804,7 +784,7 @@ class ModuleManager(object):
params='expandSubcollections=true'
)
)
return ApiParameters(resource.attrs)
return ApiParameters(params=resource.attrs)
class ArgumentSpec(object):
@ -831,7 +811,7 @@ class ArgumentSpec(object):
'weighted-least-connections-node'
]
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(
required=True,
aliases=['pool']
@ -863,44 +843,42 @@ class ArgumentSpec(object):
]
),
description=dict(),
metadata=dict(type='raw')
)
self.f5_product_name = 'bigip'
def cleanup_tokens(client):
try:
resource = client.api.shared.authz.tokens_s.token.load(
name=client.api.icrs.token
metadata=dict(type='raw'),
state=dict(
default='present',
choices=['present', 'absent']
),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
)
)
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__':

@ -65,15 +65,19 @@ options:
partition:
description:
- Device partition to manage resources on.
required: False
default: 'Common'
default: Common
version_added: 2.5
state:
description:
- When C(present), ensures that the profile exists.
- When C(absent), ensures the profile is removed.
default: present
choices:
- present
- absent
version_added: 2.5
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- Requires BIG-IP software version >= 12
requirements:
- f5-sdk >= 2.2.3
extends_documentation_fragment: f5
author:
- Tim Rupp (@caphrim007)
@ -123,77 +127,58 @@ ciphers:
import os
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.basic import env_fallback
from ansible.module_utils.six import iteritems
from collections import defaultdict
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):
api_map = {
'certKeyChain': 'cert_key_chain',
'ocspStapling': 'ocsp_stapling'
'certKeyChain': 'cert_key_chain'
}
api_attributes = [
'ciphers', 'certKeyChain', 'ocspStapling'
'ciphers', 'certKeyChain'
]
returnables = [
'ciphers', 'ocsp_stapling'
'ciphers'
]
updatables = [
'ciphers', 'cert_key_chain', 'ocsp_stapling'
'ciphers', 'cert_key_chain'
]
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
class ModuleParameters(Parameters):
def _fqdn_name(self, value):
@ -272,8 +257,10 @@ class ApiParameters(Parameters):
for x in ['cert', 'key', 'chain', 'passphrase']:
if x in item:
tmp[x] = item[x]
if 'chain' not in item:
tmp['chain'] = 'none'
result.append(tmp)
result = sorted(result, key=lambda x: x['name'])
result = sorted(result, key=lambda y: y['name'])
return result
@ -352,9 +339,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()
@ -364,7 +352,7 @@ class ModuleManager(object):
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
def _update_changed_options(self):
diff = Difference(self.want, self.have)
@ -380,7 +368,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
return True
return False
@ -397,7 +385,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))
@ -407,7 +395,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']
)
@ -422,7 +410,7 @@ class ModuleManager(object):
self._set_changed_options()
if self.want.ciphers is None:
self.want.update({'ciphers': 'DEFAULT'})
if self.client.check_mode:
if self.module.check_mode:
return True
self.create_on_device()
return True
@ -437,7 +425,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
@ -448,7 +436,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():
@ -461,7 +449,7 @@ class ModuleManager(object):
partition=self.want.partition
)
result = resource.attrs
return ApiParameters(result)
return ApiParameters(params=result)
def exists(self):
result = self.client.api.tm.ltm.profile.client_ssls.client_ssl.exists(
@ -498,7 +486,7 @@ class ModuleManager(object):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(required=True),
parent=dict(),
ciphers=dict(),
@ -510,41 +498,40 @@ class ArgumentSpec(object):
chain=dict(),
passphrase=dict()
)
),
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
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__':

@ -65,11 +65,6 @@ options:
choices:
- present
- absent
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
extends_documentation_fragment: f5
author:
- Tim Rupp (@caphrim007)
@ -107,15 +102,41 @@ level:
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.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:
from f5.bigip.contexts import TransactionContextManager
from f5.sdk_exception import LazyAttributesRequired
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
except ImportError:
HAS_F5SDK = False
@ -137,16 +158,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 level(self):
if self._values['level'] is None:
@ -155,10 +166,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):
@ -170,7 +182,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
@ -208,7 +220,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()
@ -261,7 +273,7 @@ class ModuleManager(object):
resource = getattr(provision, str(self.want.module))
resource = resource.load()
result = resource.attrs
return Parameters(result)
return Parameters(params=result)
def absent(self):
if self.exists():
@ -269,7 +281,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()
self._wait_for_module_provisioning()
@ -409,7 +421,7 @@ class ModuleManager(object):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
module=dict(
required=True,
choices=[
@ -428,31 +440,34 @@ class ArgumentSpec(object):
choices=['present', 'absent']
)
)
self.argument_spec = {}
self.argument_spec.update(f5_argument_spec)
self.argument_spec.update(argument_spec)
self.mutually_exclusive = [
['parameters', 'parameters_src']
]
self.f5_product_name = 'bigip'
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,
mutually_exclusive=spec.mutually_exclusive,
supports_check_mode=spec.supports_check_mode,
f5_product_name=spec.f5_product_name
mutually_exclusive=spec.mutually_exclusive
)
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -37,9 +37,7 @@ options:
- When C(True), includes the ASM request log data. When C(False),
excludes the ASM request log data.
default: no
choices:
- yes
- no
type: bool
max_file_size:
description:
- Max file size, in bytes, of the qkview to create. By default, no max
@ -49,16 +47,12 @@ options:
description:
- Include complete information in the qkview.
default: yes
choices:
- yes
- no
type: bool
exclude_core:
description:
- Exclude core files from the qkview.
default: no
choices:
- yes
- no
type: bool
exclude:
description:
- Exclude various file from the qkview.
@ -72,15 +66,9 @@ options:
- If C(no), the file will only be transferred if the destination does not
exist.
default: yes
choices:
- yes
- no
type: bool
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- This module does not include the "max time" or "restrict to blade" options.
requirements:
- f5-sdk >= 2.2.3
extends_documentation_fragment: f5
author:
- Tim Rupp (@caphrim007)
@ -110,20 +98,42 @@ stdout_lines:
sample: [['...', '...'], ['...'], ['...']]
'''
import re
import os
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import string_types
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 distutils.version import LooseVersion
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):
@ -207,8 +217,10 @@ 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.kwargs = kwargs
def exec_module(self):
if self.is_version_less_than_14():
@ -219,9 +231,9 @@ class ModuleManager(object):
def get_manager(self, type):
if type == 'madm':
return MadmLocationManager(self.client)
return MadmLocationManager(**self.kwargs)
elif type == 'bulk':
return BulkLocationManager(self.client)
return BulkLocationManager(**self.kwargs)
def is_version_less_than_14(self):
"""Checks to see if the TMOS version is less than 14
@ -239,9 +251,11 @@ class ModuleManager(object):
class BaseManager(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.have = None
self.want = Parameters(params=self.module.params)
self.changes = Parameters()
def _set_changed_options(self):
@ -250,7 +264,7 @@ class BaseManager(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 = []
@ -342,8 +356,8 @@ class BaseManager(object):
class BulkLocationManager(BaseManager):
def __init__(self, client):
super(BulkLocationManager, self).__init__(client)
def __init__(self, *args, **kwargs):
super(BulkLocationManager, self).__init__(**kwargs)
self.remote_dir = '/var/config/rest/bulk'
def _move_qkview_to_download(self):
@ -368,8 +382,8 @@ class BulkLocationManager(BaseManager):
class MadmLocationManager(BaseManager):
def __init__(self, client):
super(MadmLocationManager, self).__init__(client)
def __init__(self, *args, **kwargs):
super(MadmLocationManager, self).__init__(**kwargs)
self.remote_dir = '/var/config/rest/madm'
def _move_qkview_to_download(self):
@ -396,7 +410,7 @@ class MadmLocationManager(BaseManager):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
filename=dict(
default='localhost.localdomain.qkview'
),
@ -427,27 +441,30 @@ 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)
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -36,13 +36,10 @@ options:
remote syslog, if this parameter is not specified, the default value
C(none) is used.
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- Requires the netaddr Python package on the host. This is as easy as pip
install netaddr.
extends_documentation_fragment: f5
requirements:
- f5-sdk >= 2.2.0
- netaddr
author:
- Tim Rupp (@caphrim007)
@ -84,23 +81,44 @@ local_ip:
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import iteritems
HAS_DEVEL_IMPORTS = False
try:
import netaddr
HAS_NETADDR = True
# 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_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 F5ModuleError
from ansible.module_utils.six import iteritems
from collections import defaultdict
# 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 ansible.module_utils.f5_utils import HAS_F5SDK
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
import netaddr
HAS_NETADDR = True
except ImportError:
HAS_F5SDK = False
HAS_NETADDR = False
class Parameters(AnsibleF5Parameters):
@ -116,36 +134,6 @@ class Parameters(AnsibleF5Parameters):
'remoteServers'
]
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:
@ -153,16 +141,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 remote_host(self):
try:
@ -325,10 +303,11 @@ class Difference(object):
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 = Changes()
def _set_changed_options(self):
@ -337,7 +316,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)
self.changes.update({'remote_host': self.want.remote_host})
def _update_changed_options(self):
@ -354,7 +333,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = Changes(changed)
self.changes = Changes(params=changed)
self.changes.update({'remote_host': self.want.remote_host})
return True
return False
@ -386,7 +365,7 @@ class ModuleManager(object):
def create(self):
self._set_valid_defaults()
self._update_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
# This is an unnamed resource, so we only need to update
@ -418,7 +397,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
@ -449,7 +428,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():
@ -466,7 +445,7 @@ class ModuleManager(object):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
remote_host=dict(
required=True
),
@ -477,42 +456,32 @@ class ArgumentSpec(object):
choices=['absent', '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")
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__':

@ -48,11 +48,15 @@ options:
specified in either their fully qualified name (/Common/foo) or their short
name (foo). If a short name is used, the C(partition) argument will automatically
be prepended to the short name.
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
requirements:
- f5-sdk >= 3.0.4
state:
description:
- When C(present), ensures that the address list and entries exists.
- When C(absent), ensures the address list is removed.
default: present
choices:
- present
- absent
version_added: 2.5
extends_documentation_fragment: f5
author:
- Tim Rupp (@caphrim007)
@ -134,39 +138,60 @@ EXAMPLES = r'''
'''
RETURN = r'''
description:
description: The new description of the port list.
returned: changed
type: string
sample: My port list
ports:
description: The new list of ports applied to the port list
description: The new list of ports applied to the port list.
returned: changed
type: list
sample: [80, 443]
port_ranges:
description: The new list of port ranges applied to the port list
description: The new list of port ranges applied to the port list.
returned: changed
type: list
sample: [80-100, 200-8080]
ports:
description: The new list of ports applied to the port list
returned: changed
type: list
sample: [80, 443]
port_lists:
description: The new list of port list names applied to the port list
description: The new list of port list names applied to the port list.
returned: changed
type: list
sample: [/Common/list1, /Common/list2]
'''
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
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):
@ -186,51 +211,11 @@ class Parameters(AnsibleF5Parameters):
'description', 'ports', 'port_ranges', 'port_lists'
]
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 _fqdn_name(self, value):
if value is not None and not value.startswith('/'):
return '/{0}/{1}'.format(self.partition, value)
return value
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):
@property
@ -335,7 +320,7 @@ class ReportableChanges(Changes):
for item in self._values['ports']:
if '-' in item['name']:
continue
result.append(item)
result.append(item['name'])
return result
@property
@ -344,7 +329,7 @@ class ReportableChanges(Changes):
for item in self._values['ports']:
if '-' not in item['name']:
continue
result.append(item)
result.append(item['name'])
return result
@ -433,9 +418,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()
@ -445,7 +431,7 @@ class ModuleManager(object):
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
def _update_changed_options(self):
diff = Difference(self.want, self.have)
@ -461,7 +447,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
return True
return False
@ -484,7 +470,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))
@ -494,7 +480,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']
)
@ -516,13 +502,13 @@ 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
def remove(self):
if self.client.check_mode:
if self.module.check_mode:
return True
self.remove_from_device()
if self.exists():
@ -531,7 +517,7 @@ class ModuleManager(object):
def create(self):
self._set_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
self.create_on_device()
return True
@ -571,52 +557,51 @@ class ModuleManager(object):
partition=self.want.partition
)
result = resource.attrs
return ApiParameters(result)
return ApiParameters(params=result)
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(required=True),
description=dict(),
ports=dict(type='list'),
port_ranges=dict(type='list'),
port_lists=dict(type='list')
)
self.f5_product_name = 'bigip'
def cleanup_tokens(client):
try:
resource = client.api.shared.authz.tokens_s.token.load(
name=client.api.icrs.token
port_lists=dict(type='list'),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
),
state=dict(
default='present',
choices=['present', 'absent']
)
)
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__':

@ -72,13 +72,10 @@ options:
default: Common
version_added: 2.5
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- Requires the netaddr Python package on the host.
extends_documentation_fragment: f5
requirements:
- netaddr
- f5-sdk
author:
- Tim Rupp (@caphrim007)
'''
@ -218,17 +215,38 @@ vlan:
import re
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
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
try:
from netaddr import IPNetwork, AddrFormatError, IPAddress
@ -255,36 +273,6 @@ class Parameters(AnsibleF5Parameters):
'trafficGroup', 'allowService', 'vlan', 'address'
]
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:
@ -292,16 +280,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 address(self):
address = "{0}%{1}/{2}".format(
@ -424,7 +402,8 @@ class Parameters(AnsibleF5Parameters):
)
else:
result.append(svc)
return set(result)
result = sorted(list(set(result)))
return result
def _fqdn_name(self, value):
if value is not None and not value.startswith('/'):
@ -468,7 +447,9 @@ class ApiParameters(Parameters):
@property
def allow_service(self):
return self._values['allow_service']
if self._values['allow_service'] is None:
return None
return sorted(self._values['allow_service'])
@property
def trafficGroup(self):
@ -485,16 +466,17 @@ class ApiParameters(Parameters):
@allowService.setter
def allowService(self, value):
if value == 'all':
self._values['allow_service'] = set(['all'])
self._values['allow_service'] = ['all']
else:
self._values['allow_service'] = set([str(x) for x in value])
self._values['allow_service'] = sorted([str(x) for x in value])
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 = ApiParameters()
def _set_changed_options(self):
@ -503,7 +485,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 _update_changed_options(self):
diff = Difference(self.want, self.have)
@ -519,7 +501,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = ApiParameters(changed)
self.changes = ApiParameters(params=changed)
return True
return False
@ -566,14 +548,14 @@ class ModuleManager(object):
partition=self.want.partition
)
result = resource.attrs
params = ApiParameters(result)
params = ApiParameters(params=result)
return params
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
@ -599,6 +581,13 @@ class ModuleManager(object):
self.want.update({'traffic_group': '/Common/traffic-group-local-only'})
if self.want.route_domain is None:
self.want.update({'route_domain': 0})
if self.want.allow_service:
if 'all' in self.want.allow_service:
self.want.update(dict(allow_service='all'))
elif 'none' in self.want.allow_service:
self.want.update(dict(allow_service=[]))
elif 'default' in self.want.allow_service:
self.want.update(dict(allow_service=['default']))
if self.want.check_mode:
return True
self.create_on_device()
@ -616,7 +605,7 @@ class ModuleManager(object):
)
def remove(self):
if self.client.check_mode:
if self.module.check_mode:
return True
self.remove_from_device()
if self.exists():
@ -674,23 +663,20 @@ class Difference(object):
This is a convenience function to massage the values the user has
supplied so that they are formatted in such a way that BIG-IP will
accept them and apply the specified policy.
:param services: The services to format. This is always a Python set
:return:
"""
if self.want.allow_service is None:
return None
result = list(self.want.allow_service)
if self.want.allow_service == self.have.allow_service:
result = self.want.allow_service
if result[0] == 'none' and self.have.allow_service is None:
return None
elif result[0] == 'none' and self.have.allow_service is None:
return None
elif result[0] == 'all':
elif result[0] == 'all' and self.have.allow_service[0] != 'all':
return 'all'
elif result[0] == 'none':
return []
else:
return list(result)
elif self.have.allow_service is None:
return result
elif set(self.want.allow_service) != set(self.have.allow_service):
return result
@property
def netmask(self):
@ -744,39 +730,49 @@ class Difference(object):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
address=dict(),
allow_service=dict(type='list'),
name=dict(required=True),
netmask=dict(),
traffic_group=dict(),
vlan=dict(),
route_domain=dict()
route_domain=dict(),
state=dict(
default='present',
choices=['present', 'absent']
),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
)
)
self.f5_product_name = 'bigip'
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -42,13 +42,9 @@ options:
default: 'Common'
version_added: 2.5
notes:
- Requires the f5-sdk Python package on the host. This is as easy as
pip install f5-sdk
- Requires the netaddr Python package on the host. This is as easy as
pip install netaddr
extends_documentation_fragment: f5
requirements:
- f5-sdk
author:
- Tim Rupp (@caphrim007)
'''
@ -97,15 +93,38 @@ members:
import os
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.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
try:
from netaddr import IPAddress, AddrFormatError
@ -172,6 +191,10 @@ class Parameters(AnsibleF5Parameters):
)
class Changes(Parameters):
pass
class Difference(object):
def __init__(self, want, have=None):
self.want = want
@ -204,11 +227,12 @@ class Difference(object):
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.changes = Parameters()
self.want = Parameters(params=self.module.params)
self.changes = Changes()
def _set_changed_options(self):
changed = {}
@ -216,7 +240,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 = Changes(params=changed)
def _update_changed_options(self):
diff = Difference(self.want, self.have)
@ -229,7 +253,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = Parameters(changed)
self.changes = Changes(params=changed)
return True
return False
@ -259,7 +283,7 @@ class ModuleManager(object):
if self.have:
warnings += self.have._values.get('__warnings', [])
for warning in warnings:
self.client.module.deprecate(
self.module.deprecate(
msg=warning['msg'],
version=warning['version']
)
@ -282,7 +306,7 @@ class ModuleManager(object):
partition=self.want.partition
)
result = resource.attrs
return Parameters(result)
return Parameters(params=result)
def exists(self):
result = self.client.api.tm.ltm.snatpools.snatpool.exists(
@ -301,7 +325,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
@ -317,7 +341,7 @@ class ModuleManager(object):
def create(self):
self._set_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
self.create_on_device()
if not self.exists():
@ -333,7 +357,7 @@ class ModuleManager(object):
)
def remove(self):
if self.client.check_mode:
if self.module.check_mode:
return True
self.remove_from_device()
if self.exists():
@ -351,7 +375,7 @@ class ModuleManager(object):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(required=True),
members=dict(
type='list',
@ -360,36 +384,43 @@ class ArgumentSpec(object):
state=dict(
default='present',
choices=['absent', 'present']
),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
)
)
self.argument_spec = {}
self.argument_spec.update(f5_argument_spec)
self.argument_spec.update(argument_spec)
self.required_if = [
['state', 'present', ['members']]
]
self.f5_product_name = 'bigip'
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_if=spec.required_if
)
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':
main()

@ -50,14 +50,9 @@ options:
location:
description:
- Specifies the description of this system's physical location.
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 >= 2.2.0
author:
- Tim Rupp (@caphrim007)
- Tim Rupp (@caphrim007)
'''
EXAMPLES = r'''
@ -108,15 +103,37 @@ location:
sample: US West 1a
'''
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):
@ -149,23 +166,18 @@ 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 Changes(Parameters):
pass
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.changes = Parameters()
self.want = Parameters(params=self.module.params)
self.changes = Changes()
def _update_changed_options(self):
changed = {}
@ -176,7 +188,7 @@ class ModuleManager(object):
if attr1 != attr2:
changed[key] = attr1
if changed:
self.changes = Parameters(changed)
self.changes = Changes(params=changed)
return True
return False
@ -203,7 +215,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
@ -216,14 +228,14 @@ class ModuleManager(object):
def read_current_from_device(self):
resource = self.client.api.tm.sys.snmp.load()
result = resource.attrs
return Parameters(result)
return Parameters(params=result)
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.choices = ['enabled', 'disabled']
self.argument_spec = dict(
argument_spec = dict(
contact=dict(),
agent_status_traps=dict(
choices=self.choices
@ -236,27 +248,30 @@ class ArgumentSpec(object):
),
location=dict()
)
self.f5_product_name = 'bigip'
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -57,16 +57,17 @@ options:
choices:
- present
- absent
partition:
description:
- Device partition to manage resources on.
default: Common
version_added: 2.5
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- This module only supports version v1 and v2c of SNMP.
- The C(network) option is not supported on versions of BIG-IP < 12.1.0 because
the platform did not support that option until 12.1.0. If used on versions
< 12.1.0, it will simply be ignored.
extends_documentation_fragment: f5
requirements:
- f5-sdk >= 2.2.0
author:
- Tim Rupp (@caphrim007)
'''
@ -127,17 +128,39 @@ network:
sample: management
'''
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.basic import env_fallback
from distutils.version import LooseVersion
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):
@ -166,16 +189,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 NetworkedParameters(Parameters):
updatables = [
@ -222,14 +235,16 @@ class NonNetworkedParameters(Parameters):
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.kwargs = kwargs
def exec_module(self):
if self.is_version_non_networked():
manager = NonNetworkedManager(self.client)
manager = NonNetworkedManager(**self.kwargs)
else:
manager = NetworkedManager(self.client)
manager = NetworkedManager(**self.kwargs)
return manager.exec_module()
@ -249,8 +264,9 @@ class ModuleManager(object):
class BaseManager(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
def exec_module(self):
@ -286,7 +302,7 @@ class BaseManager(object):
def create(self):
self._set_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
if all(getattr(self.want, v) is None for v in self.required_resources):
raise F5ModuleError(
@ -306,7 +322,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()
return True
@ -333,7 +349,7 @@ class BaseManager(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():
@ -350,12 +366,12 @@ class BaseManager(object):
class NetworkedManager(BaseManager):
def __init__(self, client):
super(NetworkedManager, self).__init__(client)
def __init__(self, *args, **kwargs):
super(NetworkedManager, self).__init__(**kwargs)
self.required_resources = [
'version', 'community', 'destination', 'port', 'network'
]
self.want = NetworkedParameters(self.client.module.params)
self.want = NetworkedParameters(params=self.module.params)
self.changes = NetworkedParameters()
def _set_changed_options(self):
@ -364,7 +380,7 @@ class NetworkedManager(BaseManager):
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = NetworkedParameters(changed)
self.changes = NetworkedParameters(params=changed)
def _update_changed_options(self):
changed = {}
@ -375,7 +391,7 @@ class NetworkedManager(BaseManager):
if attr1 != attr2:
changed[key] = attr1
if changed:
self.changes = NetworkedParameters(changed)
self.changes = NetworkedParameters(params=changed)
return True
return False
@ -386,7 +402,7 @@ class NetworkedManager(BaseManager):
)
result = resource.attrs
self._ensure_network(result)
return NetworkedParameters(result)
return NetworkedParameters(params=result)
def _ensure_network(self, result):
# BIG-IP's value for "default" is that the key does not
@ -400,12 +416,12 @@ class NetworkedManager(BaseManager):
class NonNetworkedManager(BaseManager):
def __init__(self, client):
super(NonNetworkedManager, self).__init__(client)
def __init__(self, *args, **kwargs):
super(NonNetworkedManager, self).__init__(**kwargs)
self.required_resources = [
'version', 'community', 'destination', 'port'
]
self.want = NonNetworkedParameters(self.client.module.params)
self.want = NonNetworkedParameters(params=self.module.params)
self.changes = NonNetworkedParameters()
def _set_changed_options(self):
@ -414,7 +430,7 @@ class NonNetworkedManager(BaseManager):
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = NonNetworkedParameters(changed)
self.changes = NonNetworkedParameters(params=changed)
def _update_changed_options(self):
changed = {}
@ -425,7 +441,7 @@ class NonNetworkedManager(BaseManager):
if attr1 != attr2:
changed[key] = attr1
if changed:
self.changes = NonNetworkedParameters(changed)
self.changes = NonNetworkedParameters(params=changed)
return True
return False
@ -435,13 +451,13 @@ class NonNetworkedManager(BaseManager):
partition=self.want.partition
)
result = resource.attrs
return NonNetworkedParameters(result)
return NonNetworkedParameters(params=result)
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(
required=True
),
@ -457,26 +473,36 @@ class ArgumentSpec(object):
state=dict(
default='present',
choices=['absent', 'present']
),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
)
)
self.f5_product_name = 'bigip'
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
)
mm = ModuleManager(client)
results = mm.exec_module()
client.module.exit_json(**results)
if not HAS_F5SDK:
module.fail_json(msg="The python f5-sdk module is required")
try:
client = F5Client(**module.params)
mm = ModuleManager(module=module, client=client)
results = mm.exec_module()
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -37,12 +37,7 @@ options:
- daily
- monthly
- weekly
notes:
- Requires the f5-sdk Python package on the host This is as easy as
C(pip install f5-sdk)
extends_documentation_fragment: f5
requirements:
- f5-sdk >= 3.0.6
author:
- Tim Rupp (@caphrim007)
'''
@ -86,17 +81,37 @@ frequency:
sample: weekly
'''
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):
@ -117,46 +132,6 @@ class Parameters(AnsibleF5Parameters):
'auto_check', 'auto_phone_home', 'frequency'
]
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
class ApiParameters(Parameters):
@property
@ -241,10 +216,11 @@ class Difference(object):
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 = ModuleParameters(self.client.module.params)
self.want = ModuleParameters(params=self.module.params)
self.changes = UsableChanges()
def exec_module(self):
@ -255,7 +231,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))
@ -265,7 +241,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']
)
@ -284,7 +260,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
return True
return False
@ -298,7 +274,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
@ -311,13 +287,13 @@ class ModuleManager(object):
def read_current_from_device(self):
resource = self.client.api.tm.sys.software.update.load()
result = resource.attrs
return ApiParameters(result)
return ApiParameters(params=result)
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
auto_check=dict(
type='bool'
),
@ -328,39 +304,30 @@ class ArgumentSpec(object):
choices=['daily', 'monthly', 'weekly']
)
)
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__':

@ -21,23 +21,15 @@ description:
disk, in PEM format.
version_added: 2.2
options:
cert_content:
content:
description:
- When used instead of 'cert_src', sets the contents of a certificate directly
to the specified value. This is used with lookup plugins or for anything
with formatting or templating. Either one of C(key_src),
C(key_content), C(cert_src) or C(cert_content) must be provided when
C(state) is C(present).
key_content:
description:
- When used instead of 'key_src', sets the contents of a certificate key
directly to the specified value. This is used with lookup plugins or for
anything with formatting or templating. Either one of C(key_src),
C(key_content), C(cert_src) or C(cert_content) must be provided when
C(state) is C(present).
- Sets the contents of a certificate directly to the specified value.
This is used with lookup plugins or for anything with formatting or
- C(content) must be provided when C(state) is C(present).
aliases: ['cert_content']
state:
description:
- Certificate and key state. This determines if the provided certificate
- Certificate state. This determines if the provided certificate
and key is to be made C(present) on the device or C(absent).
default: present
choices:
@ -45,27 +37,20 @@ options:
- absent
name:
description:
- SSL Certificate Name. This is the cert/key pair name used
when importing a certificate/key into the F5. It also
determines the filenames of the objects on the LTM
(:Partition:name.cer_11111_1 and :Partition_name.key_11111_1).
- SSL Certificate Name. This is the cert name used when importing a certificate
into the F5. It also determines the filenames of the objects on the LTM.
required: True
cert_src:
description:
- This is the local filename of the certificate. Either one of C(key_src),
C(key_content), C(cert_src) or C(cert_content) must be provided when
C(state) is C(present).
key_src:
issuer_cert:
description:
- This is the local filename of the private key. Either one of C(key_src),
C(key_content), C(cert_src) or C(cert_content) must be provided when
C(state) is C(present).
passphrase:
- Issuer certificate used for OCSP monitoring.
- This parameter is only valid on versions of BIG-IP 13.0.0 or above.
version_added: 2.5
partition:
description:
- Passphrase on certificate private key
- Device partition to manage resources on.
default: Common
version_added: 2.5
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- This module does not behave like other modules that you might include in
roles where referencing files or templates first looks in the role's
files or templates directory. To have it behave that way, use the Ansible
@ -73,24 +58,13 @@ notes:
a role context.
extends_documentation_fragment: f5
requirements:
- f5-sdk >= 3.0.3
- BIG-IP >= v12
author:
- Tim Rupp (@caphrim007)
'''
EXAMPLES = r'''
- name: Import PEM Certificate from local disk
bigip_ssl_certificate:
name: certificate-name
server: lb.mydomain.com
user: admin
password: secret
state: present
cert_src: /path/to/cert.crt
key_src: /path/to/key.key
delegate_to: localhost
EXAMPLES = r'''
- name: Use a file lookup to import PEM Certificate
bigip_ssl_certificate:
name: certificate-name
@ -98,8 +72,7 @@ EXAMPLES = r'''
user: admin
password: secret
state: present
cert_content: "{{ lookup('file', '/path/to/cert.crt') }}"
key_content: "{{ lookup('file', '/path/to/key.key') }}"
content: "{{ lookup('file', '/path/to/cert.crt') }}"
delegate_to: localhost
- name: Use a file lookup to import CA certificate chain
@ -109,10 +82,10 @@ EXAMPLES = r'''
user: admin
password: secret
state: present
cert_content: "{{ lookup('file', '/path/to/ca-chain.crt') }}"
content: "{{ lookup('file', '/path/to/ca-chain.crt') }}"
delegate_to: localhost
- name: "Delete Certificate"
- name: Delete Certificate
bigip_ssl_certificate:
name: certificate-name
server: lb.mydomain.com
@ -128,38 +101,18 @@ cert_name:
returned: created
type: string
sample: cert1
key_filename:
description:
- The name of the SSL certificate key. The C(key_filename) and
C(cert_filename) will be similar to each other, however the
C(key_filename) will have a C(.key) extension.
returned: created
type: string
sample: cert1.key
key_checksum:
description: SHA1 checksum of the key that was provided.
returned: changed and created
type: string
sample: cf23df2207d99a74fbe169e3eba035e633b65d94
key_source_path:
description: Path on BIG-IP where the source of the key is stored
returned: created
type: string
sample: /var/config/rest/downloads/cert1.key
cert_filename:
filename:
description:
- The name of the SSL certificate. The C(cert_filename) and
C(key_filename) will be similar to each other, however the
C(cert_filename) will have a C(.crt) extension.
- The name of the SSL certificate.
returned: created
type: string
sample: cert1.crt
cert_checksum:
checksum:
description: SHA1 checksum of the cert that was provided.
returned: changed and created
type: string
sample: f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
cert_source_path:
source_path:
description: Path on BIG-IP where the source of the certificate is stored.
returned: created
type: string
@ -171,47 +124,58 @@ import hashlib
import os
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
HAS_DEVEL_IMPORTS = False
try:
from StringIO import StringIO
# 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:
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.f5_utils import iteritems
# 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 ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from StringIO import StringIO
except ImportError:
HAS_F5SDK = False
from io import StringIO
class Parameters(AnsibleF5Parameters):
def __init__(self, params=None):
super(Parameters, self).__init__(params)
self._values['__warnings'] = []
api_map = {
'sourcePath': 'source_path',
'issuerCert': 'issuer_cert'
}
def to_return(self):
result = {}
try:
for returnable in self.returnables:
result[returnable] = getattr(self, returnable)
result = self._filter_params(result)
except Exception:
pass
return result
updatables = ['content', 'issuer_cert']
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
returnables = [
'filename', 'checksum', 'source_path', 'issuer_cert'
]
api_attributes = ['issuerCert']
def _get_hash(self, content):
k = hashlib.sha1()
@ -223,6 +187,13 @@ class Parameters(AnsibleF5Parameters):
k.update(data.encode('utf-8'))
return k.hexdigest()
def _fqdn_name(self, value):
if value is not None and not value.startswith('/'):
return '/{0}/{1}'.format(self.partition, value)
return value
class ApiParameters(Parameters):
@property
def checksum(self):
if self._values['checksum'] is None:
@ -234,148 +205,105 @@ class Parameters(AnsibleF5Parameters):
else:
return None
@property
def filename(self):
return self._values['name']
class KeyParameters(Parameters):
api_map = {
'sourcePath': 'key_source_path'
}
updatables = ['key_source_path']
returnables = ['key_filename', 'key_checksum', 'key_source_path']
api_attributes = ['passphrase', 'sourcePath']
class ModuleParameters(Parameters):
@property
def key_filename(self):
if self.name.endswith('.key'):
return self.name
def issuer_cert(self):
if self._values['issuer_cert'] is None:
return None
name = self._fqdn_name(self._values['issuer_cert'])
if name.endswith('.crt'):
return name
else:
return self.name + '.key'
return name + '.crt'
@property
def key_checksum(self):
if self.key_content is None:
def checksum(self):
if self.content is None:
return None
return self._get_hash(self.key_content)
return self._get_hash(self.content)
@property
def key_src(self):
if self._values['key_src'] is None:
return None
self._values['__warnings'].append(
dict(
msg="The key_src param is deprecated",
version='2.4'
)
)
try:
with open(self._values['key_src']) as fh:
self.key_content = fh.read()
except IOError:
raise F5ModuleError(
"The specified 'key_src' does not exist"
)
def filename(self):
if self.name.endswith('.crt'):
return self.name
else:
return self.name + '.crt'
@property
def key_source_path(self):
def source_path(self):
result = 'file://' + os.path.join(
BaseManager.download_path,
self.key_filename
ModuleManager.download_path,
self.filename
)
return result
class CertParameters(Parameters):
api_map = {
'sourcePath': 'cert_source_path'
}
updatables = ['cert_source_path']
class Changes(Parameters):
def to_return(self):
result = {}
try:
for returnable in self.returnables:
result[returnable] = getattr(self, returnable)
result = self._filter_params(result)
except Exception:
pass
return result
returnables = ['cert_filename', 'cert_checksum', 'cert_source_path']
api_attributes = ['sourcePath']
class ReportableChanges(Changes):
pass
@property
def cert_checksum(self):
if self.cert_content is None:
return None
return self._get_hash(self.cert_content)
@property
def cert_filename(self):
if self.name.endswith('.crt'):
return self.name
else:
return self.name + '.crt'
class UsableChanges(Changes):
pass
@property
def cert_src(self):
if self._values['cert_src'] is None:
return None
self._values['__warnings'].append(
dict(
msg="The cert_src param is deprecated",
version='2.4'
)
)
class Difference(object):
def __init__(self, want, have=None):
self.want = want
self.have = have
def compare(self, param):
try:
with open(self._value['cert_src']) as fh:
self.cert_content = fh.read()
except IOError:
raise F5ModuleError(
"The specified 'cert_src' does not exist"
)
result = getattr(self, param)
return result
except AttributeError:
result = self.__default(param)
return result
def __default(self, param):
attr1 = getattr(self.want, param)
try:
attr2 = getattr(self.have, param)
if attr1 != attr2:
return attr1
except AttributeError:
return attr1
@property
def cert_source_path(self):
result = 'file://' + os.path.join(
BaseManager.download_path,
self.cert_filename
)
return result
def content(self):
if self.want.checksum != self.have.checksum:
result = dict(
checksum=self.want.checksum,
content=self.want.content
)
return result
class ModuleManager(object):
def __init__(self, client):
self.client = client
def exec_module(self):
manager1 = self.get_manager('certificate')
manager2 = self.get_manager('key')
result = self.execute_managers([manager1, manager2])
return result
def execute_managers(self, managers):
results = dict(changed=False)
for manager in managers:
result = manager.exec_module()
for k, v in iteritems(result):
if k == 'changed':
if v is True:
results['changed'] = True
else:
results[k] = v
return results
def get_manager(self, type):
if type == 'certificate':
return CertificateManager(self.client)
elif type == 'key':
return KeyManager(self.client)
class BaseManager(object):
download_path = '/var/config/rest/downloads'
def __init__(self, client):
self.client = client
self.have = None
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()
def exec_module(self):
changed = False
@ -390,20 +318,17 @@ class BaseManager(object):
except iControlUnexpectedHTTPError as e:
raise F5ModuleError(str(e))
changes = self.changes.to_return()
reportable = ReportableChanges(params=self.changes.to_return())
changes = reportable.to_return()
result.update(**changes)
result.update(dict(changed=changed))
self._announce_deprecations()
self._announce_deprecations(result)
return result
def _announce_deprecations(self):
warnings = []
if self.want:
warnings += self.want._values.get('__warnings', [])
if self.have:
warnings += self.have._values.get('__warnings', [])
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']
)
@ -416,7 +341,7 @@ class BaseManager(object):
def create(self):
self._set_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
self.create_on_device()
return True
@ -431,7 +356,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()
return True
@ -442,257 +367,138 @@ class BaseManager(object):
return False
def remove(self):
if self.client.check_mode:
if self.module.check_mode:
return True
self.remove_from_device()
return True
class CertificateManager(BaseManager):
def __init__(self, client):
super(CertificateManager, self).__init__(client)
self.want = CertParameters(self.client.module.params)
self.changes = CertParameters()
def _set_changed_options(self):
changed = {}
try:
for key in CertParameters.returnables:
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = CertParameters(changed)
except Exception:
pass
for key in Parameters.returnables:
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = UsableChanges(params=changed)
def _update_changed_options(self):
changed = {}
try:
for key in CertParameters.updatables:
if getattr(self.want, key) is not None:
attr1 = getattr(self.want, key)
attr2 = getattr(self.have, key)
if attr1 != attr2:
changed[key] = attr1
if self.want.cert_checksum != self.have.checksum:
changed['cert_checksum'] = self.want.cert_checksum
if changed:
self.changes = CertParameters(changed)
return True
except Exception:
pass
diff = Difference(self.want, self.have)
updatables = Parameters.updatables
changed = dict()
for k in updatables:
change = diff.compare(k)
if change is None:
continue
else:
if isinstance(change, dict):
changed.update(change)
else:
changed[k] = change
if changed:
self.changes = UsableChanges(params=changed)
return True
return False
def exists(self):
result = self.client.api.tm.sys.file.ssl_certs.ssl_cert.exists(
name=self.want.cert_filename,
name=self.want.filename,
partition=self.want.partition
)
return result
def present(self):
if self.want.cert_content is None:
return False
return super(CertificateManager, self).present()
def should_update(self):
result = self._update_changed_options()
if result:
return True
return False
def update_on_device(self):
content = StringIO(self.want.cert_content)
params = self.changes.api_params()
content = StringIO(self.want.content)
self.client.api.shared.file_transfer.uploads.upload_stringio(
content, self.want.cert_filename
content, self.want.filename
)
resource = self.client.api.tm.sys.file.ssl_certs.ssl_cert.load(
name=self.want.cert_filename,
name=self.want.filename,
partition=self.want.partition
)
resource.update()
resource.update(**params)
def create_on_device(self):
content = StringIO(self.want.cert_content)
content = StringIO(self.want.content)
self.client.api.shared.file_transfer.uploads.upload_stringio(
content, self.want.cert_filename
)
self.client.api.tm.sys.file.ssl_certs.ssl_cert.create(
sourcePath=self.want.cert_source_path,
name=self.want.cert_filename,
partition=self.want.partition
)
def read_current_from_device(self):
resource = self.client.api.tm.sys.file.ssl_certs.ssl_cert.load(
name=self.want.cert_filename,
partition=self.want.partition
content, self.want.filename
)
result = resource.attrs
return CertParameters(result)
def remove_from_device(self):
resource = self.client.api.tm.sys.file.ssl_certs.ssl_cert.load(
name=self.want.cert_filename,
resource = self.client.api.tm.sys.file.ssl_certs.ssl_cert.create(
sourcePath=self.want.source_path,
name=self.want.filename,
partition=self.want.partition
)
resource.delete()
def remove(self):
result = super(CertificateManager, self).remove()
if self.exists() and not self.client.check_mode:
raise F5ModuleError("Failed to delete the certificate")
return result
class KeyManager(BaseManager):
def __init__(self, client):
super(KeyManager, self).__init__(client)
self.want = KeyParameters(self.client.module.params)
self.changes = KeyParameters()
def _set_changed_options(self):
changed = {}
try:
for key in KeyParameters.returnables:
if getattr(self.want, key) is not None:
changed[key] = getattr(self.want, key)
if changed:
self.changes = KeyParameters(changed)
except Exception:
pass
def _update_changed_options(self):
changed = {}
try:
for key in KeyParameters.updatables:
if getattr(self.want, key) is not None:
attr1 = getattr(self.want, key)
attr2 = getattr(self.have, key)
if attr1 != attr2:
changed[key] = attr1
if self.want.key_checksum != self.have.checksum:
changed['key_checksum'] = self.want.key_checksum
if changed:
self.changes = KeyParameters(changed)
return True
except Exception:
pass
return False
def should_update(self):
result = self._update_changed_options()
if result:
return True
return False
def update_on_device(self):
content = StringIO(self.want.key_content)
self.client.api.shared.file_transfer.uploads.upload_stringio(
content, self.want.key_filename
)
resource = self.client.api.tm.sys.file.ssl_keys.ssl_key.load(
name=self.want.key_filename,
partition=self.want.partition
)
resource.update()
def exists(self):
result = self.client.api.tm.sys.file.ssl_keys.ssl_key.exists(
name=self.want.key_filename,
partition=self.want.partition
)
return result
def present(self):
if self.want.key_content is None:
return False
return super(KeyManager, self).present()
# This needs to be done because of the way that BIG-IP creates certificates.
#
# The extra params (such as OCSP and issuer stuff) are not available in the
# payload. In a nutshell, the available resource attributes *change* after
# a create so that *more* are available.
params = self.want.api_params()
if params:
resource.update(**params)
def read_current_from_device(self):
resource = self.client.api.tm.sys.file.ssl_keys.ssl_key.load(
name=self.want.key_filename,
partition=self.want.partition
resource = self.client.api.tm.sys.file.ssl_certs.ssl_cert.load(
name=self.want.filename,
partition=self.want.partition,
requests_params=dict(
params='expandSubcollections=true'
)
)
result = resource.attrs
return KeyParameters(result)
def create_on_device(self):
content = StringIO(self.want.key_content)
self.client.api.shared.file_transfer.uploads.upload_stringio(
content, self.want.key_filename
)
self.client.api.tm.sys.file.ssl_keys.ssl_key.create(
sourcePath=self.want.key_source_path,
name=self.want.key_filename,
partition=self.want.partition
)
return ApiParameters(params=result)
def remove_from_device(self):
resource = self.client.api.tm.sys.file.ssl_keys.ssl_key.load(
name=self.want.key_filename,
resource = self.client.api.tm.sys.file.ssl_certs.ssl_cert.load(
name=self.want.filename,
partition=self.want.partition
)
resource.delete()
def remove(self):
result = super(KeyManager, self).remove()
if self.exists() and not self.client.check_mode:
raise F5ModuleError("Failed to delete the key")
return result
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(
required=True
),
cert_content=dict(aliases=['content']),
cert_src=dict(
type='path',
removed_in_version='2.4'
),
key_content=dict(),
key_src=dict(
type='path',
removed_in_version='2.4'
),
passphrase=dict(
no_log=True
),
content=dict(aliases=['cert_content']),
state=dict(
default='present',
choices=['absent', 'present']
),
issuer_cert=dict(),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
)
)
self.mutually_exclusive = [
['key_content', 'key_src'],
['cert_content', 'cert_src']
]
self.f5_product_name = 'bigip'
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,
mutually_exclusive=spec.mutually_exclusive,
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -43,9 +43,12 @@ options:
passphrase:
description:
- Passphrase on key.
partition:
description:
- Device partition to manage resources on.
default: Common
version_added: 2.5
notes:
- Requires the f5-sdk Python package on the host. This is as easy as pip
install f5-sdk.
- This module does not behave like other modules that you might include in
roles where referencing files or templates first looks in the role's
files or templates directory. To have it behave that way, use the Ansible
@ -53,7 +56,6 @@ notes:
a role context.
extends_documentation_fragment: f5
requirements:
- f5-sdk >= 1.5.0
- BIG-IP >= v12
author:
- Tim Rupp (@caphrim007)
@ -101,25 +103,47 @@ key_source_path:
sample: /var/config/rest/downloads/cert1.key
'''
import hashlib
import os
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
HAS_DEVEL_IMPORTS = False
try:
from StringIO import StringIO
# 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:
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
# 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 ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from StringIO import StringIO
except ImportError:
HAS_F5SDK = False
from io import StringIO
class Parameters(AnsibleF5Parameters):
@ -145,16 +169,6 @@ class Parameters(AnsibleF5Parameters):
pass
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
def _get_hash(self, content):
k = hashlib.sha1()
s = StringIO(content)
@ -198,12 +212,17 @@ class Parameters(AnsibleF5Parameters):
return None
class Changes(Parameters):
pass
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.changes = Parameters()
self.want = Parameters(params=self.module.params)
self.changes = Changes()
def exec_module(self):
changed = False
@ -230,7 +249,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 = Changes(params=changed)
except Exception:
pass
@ -246,7 +265,7 @@ class ModuleManager(object):
if self.want.key_checksum != self.have.checksum:
changed['key_checksum'] = self.want.key_checksum
if changed:
self.changes = Parameters(changed)
self.changes = Changes(params=changed)
return True
except Exception:
pass
@ -286,7 +305,7 @@ class ModuleManager(object):
if self.want.content is None:
return False
self._set_changed_options()
if self.client.check_mode:
if self.module.check_mode:
return True
self.create_on_device()
return True
@ -297,13 +316,13 @@ class ModuleManager(object):
partition=self.want.partition
)
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
@ -332,7 +351,7 @@ class ModuleManager(object):
resource.delete()
def remove(self):
if self.client.check_mode:
if self.module.check_mode:
return True
self.remove_from_device()
if self.exists():
@ -343,7 +362,7 @@ class ModuleManager(object):
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
name=dict(
required=True
),
@ -357,29 +376,36 @@ class ArgumentSpec(object):
required=False,
default='present',
choices=['absent', 'present']
),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
)
)
self.f5_product_name = 'bigip'
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()
client.module.exit_json(**results)
except F5ModuleError as e:
client.module.fail_json(msg=str(e))
cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
module.fail_json(msg=str(ex))
if __name__ == '__main__':

@ -41,19 +41,6 @@ lib/ansible/modules/net_tools/cloudflare_dns.py E317
lib/ansible/modules/net_tools/haproxy.py E317
lib/ansible/modules/net_tools/omapi_host.py E317
lib/ansible/modules/network/cloudengine/ce_reboot.py E317
lib/ansible/modules/network/f5/bigip_pool.py E321
lib/ansible/modules/network/f5/bigip_profile_client_ssl.py E321
lib/ansible/modules/network/f5/bigip_provision.py E321
lib/ansible/modules/network/f5/bigip_qkview.py E321
lib/ansible/modules/network/f5/bigip_remote_syslog.py E321
lib/ansible/modules/network/f5/bigip_security_port_list.py E321
lib/ansible/modules/network/f5/bigip_selfip.py E321
lib/ansible/modules/network/f5/bigip_snat_pool.py E321
lib/ansible/modules/network/f5/bigip_snmp.py E321
lib/ansible/modules/network/f5/bigip_snmp_trap.py E321
lib/ansible/modules/network/f5/bigip_software_update.py E321
lib/ansible/modules/network/f5/bigip_ssl_certificate.py E321
lib/ansible/modules/network/f5/bigip_ssl_key.py E321
lib/ansible/modules/network/f5/bigip_sys_db.py E321
lib/ansible/modules/network/f5/bigip_sys_global.py E321
lib/ansible/modules/network/f5/bigip_traffic_group.py E321

@ -0,0 +1,42 @@
{
"kind": "tm:sys:file:ssl-cert:ssl-certstate",
"name": "ocsp.example.com.crt",
"partition": "Common",
"fullPath": "/Common/ocsp.example.com.crt",
"generation": 548,
"selfLink": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ocsp.example.com.crt?ver=13.0.0",
"certValidationOptions": [
"ocsp"
],
"certificateKeyCurveName": "none",
"certificateKeySize": 4096,
"checksum": "SHA1:2113:b84ae5ed7e236b35206b2ff61289df9547d5afa3",
"createTime": "2017-10-25T20:56:09Z",
"createdBy": "admin",
"expirationDate": 1545199767,
"expirationString": "Dec 19 06:09:27 2018 GMT",
"isBundle": "false",
"issuer": "CN=Alice Ltd Intermediate CA,OU=Alice Ltd Certificate Authority,O=Alice Ltd,ST=England,C=GB",
"issuerCert": "/Common/intermediate.crt",
"issuerCertReference": {
"link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~intermediate.crt?ver=13.0.0"
},
"keyType": "rsa-public",
"lastUpdateTime": "2017-10-25T20:56:09Z",
"mode": 33188,
"revision": 1,
"serialNumber": "4096",
"size": 2113,
"sourcePath": "file:///var/config/rest/downloads/ocsp.example.com.crt",
"subject": "CN=ocsp.example.com,OU=Alice Ltd Certificate Authority,O=Alice Ltd,ST=England,C=GB",
"updatedBy": "admin",
"version": 3,
"bundleCertificatesReference": {
"link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ocsp.example.com.crt/bundle-certificates?ver=13.0.0",
"isSubcollection": true
},
"certValidatorsReference": {
"link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ocsp.example.com.crt/cert-validators?ver=13.0.0",
"isSubcollection": true
}
}

@ -18,15 +18,15 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.f5_utils import F5ModuleError
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_pool import ApiParameters
from library.bigip_pool import ModuleParameters
from library.bigip_pool import ModuleManager
from library.bigip_pool import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -34,7 +34,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_pool import ModuleParameters
from ansible.modules.network.f5.bigip_pool import ModuleManager
from ansible.modules.network.f5.bigip_pool import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -72,7 +73,7 @@ class TestParameters(unittest.TestCase):
service_down_action='drop'
)
p = ModuleParameters(args)
p = ModuleParameters(params=args)
assert p.monitor_type == 'm_of_n'
assert p.quorum == 1
assert p.monitors == 'min 1 of { /Common/Fake /Common/Fake2 }'
@ -88,7 +89,7 @@ class TestParameters(unittest.TestCase):
serviceDownAction='drop'
)
p = ApiParameters(args)
p = ApiParameters(params=args)
assert p.monitors == '/Common/Fake and /Common/Fake2'
assert p.slow_ramp_time == 200
assert p.reselect_tries == 5
@ -99,7 +100,7 @@ class TestParameters(unittest.TestCase):
lb_method='obscure_hyphenated_fake_method',
)
with pytest.raises(F5ModuleError):
p = ModuleParameters(args)
p = ModuleParameters(params=args)
assert p.lb_method == 'foo'
def test_unknown_api_lb_method(self):
@ -107,12 +108,10 @@ class TestParameters(unittest.TestCase):
loadBalancingMode='obscure_hypenated_fake_method'
)
with pytest.raises(F5ModuleError):
p = ApiParameters(args)
p = ApiParameters(params=args)
assert p.lb_method == 'foo'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -132,13 +131,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -163,13 +161,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -191,13 +188,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -220,13 +216,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -247,13 +242,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -276,13 +270,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -304,14 +297,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
current = ApiParameters(load_fixture('load_ltm_pool.json'))
current = ApiParameters(params=load_fixture('load_ltm_pool.json'))
mm.update_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=True)
@ -332,13 +324,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -360,13 +351,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -388,13 +378,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -417,13 +406,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)
@ -443,13 +431,12 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.create_on_device = Mock(return_value=True)
mm.exists = Mock(return_value=False)

@ -18,14 +18,15 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_profile_client_ssl import ModuleParameters
from library.bigip_profile_client_ssl import ApiParameters
from library.bigip_profile_client_ssl import ModuleManager
from library.bigip_profile_client_ssl import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -33,7 +34,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_profile_client_ssl import ApiParameters
from ansible.modules.network.f5.bigip_profile_client_ssl import ModuleManager
from ansible.modules.network.f5.bigip_profile_client_ssl import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -75,20 +77,18 @@ class TestParameters(unittest.TestCase):
]
)
p = ModuleParameters(args)
p = ModuleParameters(params=args)
assert p.name == 'foo'
assert p.parent == '/Common/bar'
assert p.ciphers == '!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA'
def test_api_parameters(self):
args = load_fixture('load_ltm_profile_clientssl.json')
p = ApiParameters(args)
p = ApiParameters(params=args)
assert p.name == 'foo'
assert p.ciphers == 'DEFAULT'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -112,12 +112,11 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.exists = Mock(return_value=False)

@ -17,20 +17,22 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_provision import Parameters
from library.bigip_provision import ModuleManager
from library.bigip_provision import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
from ansible.modules.network.f5.bigip_provision import Parameters
from ansible.modules.network.f5.bigip_provision import ModuleManager
from ansible.modules.network.f5.bigip_provision import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -65,12 +67,10 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.module == 'gtm'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -93,12 +93,11 @@ class TestManager(unittest.TestCase):
level='none'
)
)
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.update_on_device = Mock(return_value=True)
@ -130,9 +129,8 @@ class TestManager(unittest.TestCase):
))
with patch('ansible.module_utils.basic.AnsibleModule.fail_json') as mo:
AnsibleF5Client(
AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
)
mo.assert_not_called()

@ -17,7 +17,7 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_qkview import Parameters
@ -25,7 +25,8 @@ try:
from library.bigip_qkview import MadmLocationManager
from library.bigip_qkview import BulkLocationManager
from library.bigip_qkview import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -34,7 +35,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_qkview import MadmLocationManager
from ansible.modules.network.f5.bigip_qkview import BulkLocationManager
from ansible.modules.network.f5.bigip_qkview import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -73,7 +75,7 @@ class TestParameters(unittest.TestCase):
exclude=['audit', 'secure'],
dest='/tmp/foo.qkview'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.filename == 'foo.qkview'
assert p.asm_request_log is None
assert p.max_file_size == '-s 1024'
@ -89,12 +91,10 @@ class TestParameters(unittest.TestCase):
args = dict(
asm_request_log=True,
)
p = Parameters(args)
p = Parameters(params=args)
assert p.asm_request_log == '-o asm-request-log'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestMadmLocationManager(unittest.TestCase):
def setUp(self):
@ -108,14 +108,13 @@ class TestMadmLocationManager(unittest.TestCase):
password='password'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
tm = MadmLocationManager(client)
tm = MadmLocationManager(module=module, params=module.params)
tm.exists = Mock(return_value=False)
tm.execute_on_device = Mock(return_value=True)
tm._move_qkview_to_download = Mock(return_value=True)
@ -123,7 +122,7 @@ class TestMadmLocationManager(unittest.TestCase):
tm._delete_qkview = Mock(return_value=True)
# Override methods to force specific logic in the module to happen
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.is_version_less_than_14 = Mock(return_value=True)
mm.get_manager = Mock(return_value=tm)
@ -134,8 +133,6 @@ class TestMadmLocationManager(unittest.TestCase):
assert results['changed'] is False
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestBulkLocationManager(unittest.TestCase):
def setUp(self):
@ -149,14 +146,13 @@ class TestBulkLocationManager(unittest.TestCase):
password='password'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
tm = BulkLocationManager(client)
tm = BulkLocationManager(module=module, params=module.params)
tm.exists = Mock(return_value=False)
tm.execute_on_device = Mock(return_value=True)
tm._move_qkview_to_download = Mock(return_value=True)
@ -164,7 +160,7 @@ class TestBulkLocationManager(unittest.TestCase):
tm._delete_qkview = Mock(return_value=True)
# Override methods to force specific logic in the module to happen
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.is_version_less_than_14 = Mock(return_value=False)
mm.get_manager = Mock(return_value=tm)

@ -17,7 +17,7 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_remote_syslog import Parameters
@ -25,7 +25,8 @@ try:
from library.bigip_remote_syslog import ArgumentSpec
from library.bigip_remote_syslog import HAS_F5SDK
from library.bigip_remote_syslog import HAS_NETADDR
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -34,7 +35,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_remote_syslog import ArgumentSpec
from ansible.modules.network.f5.bigip_remote_syslog import HAS_F5SDK
from ansible.modules.network.f5.bigip_remote_syslog import HAS_NETADDR
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -73,7 +75,7 @@ class TestParameters(unittest.TestCase):
local_ip='1.1.1.1'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.remote_host == '10.10.10.10'
assert p.remote_port == 514
assert p.local_ip == '1.1.1.1'
@ -90,12 +92,10 @@ class TestParameters(unittest.TestCase):
]
)
p = Parameters(args)
p = Parameters(params=args)
assert len(p.remoteServers) == 1
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -109,14 +109,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.exists = Mock(side_effect=[False, True])
mm.update_on_device = Mock(return_value=True)
@ -132,15 +131,14 @@ class TestManager(unittest.TestCase):
user='admin'
))
current = Parameters(load_fixture('load_tm_sys_syslog.json'))
client = AnsibleF5Client(
current = Parameters(params=load_fixture('load_tm_sys_syslog.json'))
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.exists = Mock(return_value=True)
mm.read_current_from_device = Mock(return_value=current)
@ -157,15 +155,14 @@ class TestManager(unittest.TestCase):
user='admin'
))
current = Parameters(load_fixture('load_tm_sys_syslog.json'))
client = AnsibleF5Client(
current = Parameters(params=load_fixture('load_tm_sys_syslog.json'))
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.exists = Mock(return_value=True)
mm.read_current_from_device = Mock(return_value=current)
mm.update_on_device = Mock(return_value=True)
@ -184,15 +181,14 @@ class TestManager(unittest.TestCase):
user='admin'
))
current = Parameters(load_fixture('load_tm_sys_syslog.json'))
client = AnsibleF5Client(
current = Parameters(params=load_fixture('load_tm_sys_syslog.json'))
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.exists = Mock(return_value=True)
mm.read_current_from_device = Mock(return_value=current)
mm.update_on_device = Mock(return_value=True)

@ -18,15 +18,15 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.f5_utils import F5ModuleError
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_security_port_list import ApiParameters
from library.bigip_security_port_list import ModuleParameters
from library.bigip_security_port_list import ModuleManager
from library.bigip_security_port_list import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -35,7 +35,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_security_port_list import ModuleParameters
from ansible.modules.network.f5.bigip_security_port_list import ModuleManager
from ansible.modules.network.f5.bigip_security_port_list import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -72,7 +73,7 @@ class TestParameters(unittest.TestCase):
port_lists=['/Common/foo', 'foo']
)
p = ModuleParameters(args)
p = ModuleParameters(params=args)
assert p.name == 'foo'
assert p.description == 'this is a description'
assert len(p.ports) == 4
@ -82,7 +83,7 @@ class TestParameters(unittest.TestCase):
def test_api_parameters(self):
args = load_fixture('load_security_port_list_1.json')
p = ApiParameters(args)
p = ApiParameters(params=args)
assert len(p.ports) == 4
assert len(p.port_ranges) == 3
assert len(p.port_lists) == 1
@ -91,8 +92,6 @@ class TestParameters(unittest.TestCase):
assert p.port_lists[0] == '/Common/_sys_self_allow_tcp_defaults'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -105,17 +104,16 @@ class TestManager(unittest.TestCase):
ports=[1, 2, 3, 4],
port_ranges=['10-20', '30-40', '50-60'],
port_lists=['/Common/foo', 'foo'],
password='passsword',
password='password',
server='localhost',
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.exists = Mock(side_effect=[False, True])

@ -18,15 +18,15 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.f5_utils import F5ModuleError
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_selfip import Parameters
from library.bigip_selfip import ApiParameters
from library.bigip_selfip import ModuleManager
from library.bigip_selfip import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -34,7 +34,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_selfip import ApiParameters
from ansible.modules.network.f5.bigip_selfip import ModuleManager
from ansible.modules.network.f5.bigip_selfip import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -78,9 +79,9 @@ class TestParameters(unittest.TestCase):
traffic_group='traffic-group-local-only',
vlan='net1'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.address == '10.10.10.10%1/24'
assert p.allow_service == set(['tcp:80', 'udp:53', 'gre:0'])
assert p.allow_service == ['gre:0', 'tcp:80', 'udp:53']
assert p.name == 'net1'
assert p.netmask == 24
assert p.route_domain == 1
@ -95,9 +96,9 @@ class TestParameters(unittest.TestCase):
'grp'
]
)
p = Parameters(args)
p = Parameters(params=args)
with pytest.raises(F5ModuleError) as ex:
assert p.allow_service == set(['tcp:80', 'udp:53', 'grp'])
assert p.allow_service == ['grp', 'tcp:80', 'udp:53']
assert 'The provided protocol' in str(ex)
def test_api_parameters(self):
@ -113,9 +114,9 @@ class TestParameters(unittest.TestCase):
trafficGroup='/Common/traffic-group-local-only',
vlan='net1'
)
p = ApiParameters(args)
p = ApiParameters(params=args)
assert p.address == '10.10.10.10%1/24'
assert p.allow_service == set(['tcp:80', 'udp:53', 'gre'])
assert p.allow_service == ['gre', 'tcp:80', 'udp:53']
assert p.name == 'net1'
assert p.netmask == 24
assert p.route_domain == 1
@ -123,8 +124,6 @@ class TestParameters(unittest.TestCase):
assert p.vlan == '/Common/net1'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -150,12 +149,11 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.exists = Mock(side_effect=[False, True])
@ -185,14 +183,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
current = ApiParameters(load_fixture('load_tm_net_self.json'))
current = ApiParameters(params=load_fixture('load_tm_net_self.json'))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.exists = Mock(side_effect=[True, True])

@ -17,20 +17,22 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_snat_pool import Parameters
from library.bigip_snat_pool import ModuleManager
from library.bigip_snat_pool import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
from ansible.modules.network.f5.bigip_snat_pool import Parameters
from ansible.modules.network.f5.bigip_snat_pool import ModuleManager
from ansible.modules.network.f5.bigip_snat_pool import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -65,7 +67,7 @@ class TestParameters(unittest.TestCase):
members=['10.10.10.10', '20.20.20.20'],
partition='Common'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.name == 'my-snat-pool'
assert p.state == 'present'
assert len(p.members) == 2
@ -76,14 +78,12 @@ class TestParameters(unittest.TestCase):
args = dict(
members=['/Common/10.10.10.10', '/foo/20.20.20.20']
)
p = Parameters(args)
p = Parameters(params=args)
assert len(p.members) == 2
assert '/Common/10.10.10.10' in p.members
assert '/Common/20.20.20.20' in p.members
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -99,12 +99,11 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.exists = Mock(side_effect=[False, True])
@ -127,14 +126,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
current = Parameters(load_fixture('load_ltm_snatpool.json'))
current = Parameters(params=load_fixture('load_ltm_snatpool.json'))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.exists = Mock(side_effect=[True, True])
@ -154,14 +152,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
current = Parameters(load_fixture('load_ltm_snatpool.json'))
current = Parameters(params=load_fixture('load_ltm_snatpool.json'))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.read_current_from_device = Mock(return_value=current)

@ -17,20 +17,22 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_snmp import Parameters
from library.bigip_snmp import ModuleManager
from library.bigip_snmp import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
from ansible.modules.network.f5.bigip_snmp import Parameters
from ansible.modules.network.f5.bigip_snmp import ModuleManager
from ansible.modules.network.f5.bigip_snmp import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -69,7 +71,7 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.agent_status_traps == 'enabled'
assert p.agent_authentication_traps == 'enabled'
assert p.device_warning_traps == 'enabled'
@ -85,7 +87,7 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.agent_status_traps == 'disabled'
assert p.agent_authentication_traps == 'disabled'
assert p.device_warning_traps == 'disabled'
@ -98,7 +100,7 @@ class TestParameters(unittest.TestCase):
sysLocation='Lunar orbit',
sysContact='Alice@foo.org',
)
p = Parameters(args)
p = Parameters(params=args)
assert p.agent_status_traps == 'enabled'
assert p.agent_authentication_traps == 'enabled'
assert p.device_warning_traps == 'enabled'
@ -111,14 +113,12 @@ class TestParameters(unittest.TestCase):
authTrap='disabled',
bigipTraps='disabled',
)
p = Parameters(args)
p = Parameters(params=args)
assert p.agent_status_traps == 'disabled'
assert p.agent_authentication_traps == 'disabled'
assert p.device_warning_traps == 'disabled'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -140,12 +140,11 @@ class TestManager(unittest.TestCase):
)
)
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.update_on_device = Mock(return_value=True)

@ -18,7 +18,7 @@ from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.compat.tests.mock import DEFAULT
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_snmp_trap import NetworkedParameters
@ -27,7 +27,8 @@ try:
from library.bigip_snmp_trap import NetworkedManager
from library.bigip_snmp_trap import NonNetworkedManager
from library.bigip_snmp_trap import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -37,7 +38,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_snmp_trap import NetworkedManager
from ansible.modules.network.f5.bigip_snmp_trap import NonNetworkedManager
from ansible.modules.network.f5.bigip_snmp_trap import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -77,7 +79,7 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = NetworkedParameters(args)
p = NetworkedParameters(params=args)
assert p.name == 'foo'
assert p.snmp_version == '1'
assert p.community == 'public'
@ -97,7 +99,7 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = NonNetworkedParameters(args)
p = NonNetworkedParameters(params=args)
assert p.name == 'foo'
assert p.snmp_version == '1'
assert p.community == 'public'
@ -114,7 +116,7 @@ class TestParameters(unittest.TestCase):
version=1,
port=1000
)
p = NetworkedParameters(args)
p = NetworkedParameters(params=args)
assert p.name == 'foo'
assert p.snmp_version == '1'
assert p.community == 'public'
@ -123,8 +125,6 @@ class TestParameters(unittest.TestCase):
assert p.network == 'other'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -143,14 +143,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods to force specific logic in the module to happen
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.is_version_non_networked = Mock(return_value=False)
patches = dict(
@ -178,14 +177,13 @@ class TestManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods to force specific logic in the module to happen
mm = ModuleManager(client)
mm = ModuleManager(module=module)
mm.is_version_non_networked = Mock(return_value=True)
patches = dict(

@ -17,14 +17,15 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_software_update import ApiParameters
from library.bigip_software_update import ModuleParameters
from library.bigip_software_update import ModuleManager
from library.bigip_software_update import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -32,7 +33,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_software_update import ModuleParameters
from ansible.modules.network.f5.bigip_software_update import ModuleManager
from ansible.modules.network.f5.bigip_software_update import ArgumentSpec
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -65,7 +67,7 @@ class TestParameters(unittest.TestCase):
auto_check=True,
frequency="daily"
)
p = ModuleParameters(args)
p = ModuleParameters(params=args)
assert p.auto_check == 'enabled'
assert p.frequency == 'daily'
@ -74,13 +76,11 @@ class TestParameters(unittest.TestCase):
autoCheck="enabled",
frequency="daily"
)
p = ApiParameters(args)
p = ApiParameters(params=args)
assert p.auto_check == 'enabled'
assert p.frequency == 'daily'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestManager(unittest.TestCase):
def setUp(self):
@ -98,14 +98,13 @@ class TestManager(unittest.TestCase):
# Configure the parameters that would be returned by querying the
# remote device
current = ApiParameters(load_fixture('load_sys_software_update.json'))
current = ApiParameters(params=load_fixture('load_sys_software_update.json'))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
mm = ModuleManager(client)
mm = ModuleManager(module=module)
# Override methods to force specific logic in the module to happen
mm.update_on_device = Mock(return_value=True)

@ -17,26 +17,26 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_ssl_certificate import ArgumentSpec
from library.bigip_ssl_certificate import KeyParameters
from library.bigip_ssl_certificate import CertParameters
from library.bigip_ssl_certificate import CertificateManager
from library.bigip_ssl_certificate import ApiParameters
from library.bigip_ssl_certificate import ModuleParameters
from library.bigip_ssl_certificate import ModuleManager
from library.bigip_ssl_certificate import HAS_F5SDK
from library.bigip_ssl_certificate import KeyManager
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
from ansible.modules.network.f5.bigip_ssl_certificate import ArgumentSpec
from ansible.modules.network.f5.bigip_ssl_certificate import KeyParameters
from ansible.modules.network.f5.bigip_ssl_certificate import CertParameters
from ansible.modules.network.f5.bigip_ssl_certificate import CertificateManager
from ansible.modules.network.f5.bigip_ssl_certificate import ApiParameters
from ansible.modules.network.f5.bigip_ssl_certificate import ModuleParameters
from ansible.modules.network.f5.bigip_ssl_certificate import ModuleManager
from ansible.modules.network.f5.bigip_ssl_certificate import HAS_F5SDK
from ansible.modules.network.f5.bigip_ssl_certificate import KeyManager
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -64,10 +64,10 @@ def load_fixture(name):
class TestParameters(unittest.TestCase):
def test_module_parameters_key(self):
key_content = load_fixture('create_insecure_key1.key')
def test_module_parameters_cert(self):
cert_content = load_fixture('create_insecure_cert1.crt')
args = dict(
key_content=key_content,
content=cert_content,
name="cert1",
partition="Common",
state="present",
@ -75,45 +75,33 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = KeyParameters(args)
p = ModuleParameters(params=args)
assert p.name == 'cert1'
assert p.key_filename == 'cert1.key'
assert '-----BEGIN RSA PRIVATE KEY-----' in p.key_content
assert '-----END RSA PRIVATE KEY-----' in p.key_content
assert p.key_checksum == '91bdddcf0077e2bb2a0258aae2ae3117be392e83'
assert p.filename == 'cert1.crt'
assert 'Signature Algorithm' in p.content
assert '-----BEGIN CERTIFICATE-----' in p.content
assert '-----END CERTIFICATE-----' in p.content
assert p.checksum == '1e55aa57ee166a380e756b5aa4a835c5849490fe'
assert p.state == 'present'
assert p.user == 'admin'
assert p.server == 'localhost'
assert p.password == 'password'
assert p.partition == 'Common'
def test_module_parameters_cert(self):
cert_content = load_fixture('create_insecure_cert1.crt')
def test_module_issuer_cert_key(self):
args = dict(
cert_content=cert_content,
name="cert1",
issuer_cert='foo',
partition="Common",
state="present",
password='password',
server='localhost',
user='admin'
)
p = CertParameters(args)
assert p.name == 'cert1'
assert p.cert_filename == 'cert1.crt'
assert 'Signature Algorithm' in p.cert_content
assert '-----BEGIN CERTIFICATE-----' in p.cert_content
assert '-----END CERTIFICATE-----' in p.cert_content
assert p.cert_checksum == '1e55aa57ee166a380e756b5aa4a835c5849490fe'
assert p.state == 'present'
assert p.user == 'admin'
assert p.server == 'localhost'
assert p.password == 'password'
assert p.partition == 'Common'
p = ModuleParameters(params=args)
assert p.issuer_cert == '/Common/foo.crt'
def test_api_issuer_cert_key(self):
args = load_fixture('load_sys_file_ssl_cert_with_issuer_cert.json')
p = ApiParameters(params=args)
assert p.issuer_cert == '/Common/intermediate.crt'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestCertificateManager(unittest.TestCase):
def setUp(self):
@ -122,111 +110,47 @@ class TestCertificateManager(unittest.TestCase):
def test_import_certificate_and_key_no_key_passphrase(self, *args):
set_module_args(dict(
name='foo',
cert_content=load_fixture('cert1.crt'),
key_content=load_fixture('cert1.key'),
content=load_fixture('cert1.crt'),
state='present',
password='password',
server='localhost',
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
cm = CertificateManager(client)
cm.exists = Mock(side_effect=[False, True])
cm.create_on_device = Mock(return_value=True)
mm = ModuleManager(module=module)
mm.exists = Mock(side_effect=[False, True])
mm.create_on_device = Mock(return_value=True)
results = cm.exec_module()
results = mm.exec_module()
assert results['changed'] is True
def test_import_certificate_chain(self, *args):
set_module_args(dict(
name='foo',
cert_content=load_fixture('chain1.crt'),
state='present',
password='password',
server='localhost',
user='admin'
))
client = AnsibleF5Client(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
)
# Override methods in the specific type of manager
cm = CertificateManager(client)
cm.exists = Mock(side_effect=[False, True])
cm.create_on_device = Mock(return_value=True)
results = cm.exec_module()
assert results['changed'] is True
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestKeyManager(unittest.TestCase):
def setUp(self):
self.spec = ArgumentSpec()
def test_import_certificate_and_key_no_key_passphrase(self, *args):
set_module_args(dict(
name='foo',
cert_content=load_fixture('cert1.crt'),
key_content=load_fixture('cert1.key'),
state='present',
password='password',
server='localhost',
user='admin'
))
client = AnsibleF5Client(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
)
# Override methods in the specific type of manager
cm = KeyManager(client)
cm.exists = Mock(side_effect=[False, True])
cm.create_on_device = Mock(return_value=True)
results = cm.exec_module()
assert results['changed'] is True
def test_update_certificate_new_certificate_and_key_password_protected_key(self, *args):
set_module_args(dict(
name='foo',
cert_content=load_fixture('cert2.crt'),
key_content=load_fixture('cert2.key'),
content=load_fixture('chain1.crt'),
state='present',
passphrase='keypass',
password='password',
server='localhost',
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
cm = KeyManager(client)
cm.exists = Mock(side_effect=[False, True])
cm.create_on_device = Mock(return_value=True)
mm = ModuleManager(module=module)
mm.exists = Mock(side_effect=[False, True])
mm.create_on_device = Mock(return_value=True)
results = cm.exec_module()
results = mm.exec_module()
assert results['changed'] is True

@ -17,14 +17,15 @@ if sys.version_info < (2, 7):
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import Mock
from ansible.compat.tests.mock import patch
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.basic import AnsibleModule
try:
from library.bigip_ssl_key import ArgumentSpec
from library.bigip_ssl_key import Parameters
from library.bigip_ssl_key import ModuleManager
from library.bigip_ssl_key import HAS_F5SDK
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
from test.unit.modules.utils import set_module_args
except ImportError:
try:
@ -32,7 +33,8 @@ except ImportError:
from ansible.modules.network.f5.bigip_ssl_key import Parameters
from ansible.modules.network.f5.bigip_ssl_key import ModuleManager
from ansible.modules.network.f5.bigip_ssl_key import HAS_F5SDK
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
from units.modules.utils import set_module_args
except ImportError:
raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
@ -71,7 +73,7 @@ class TestParameters(unittest.TestCase):
server='localhost',
user='admin'
)
p = Parameters(args)
p = Parameters(params=args)
assert p.name == 'cert1'
assert p.key_filename == 'cert1.key'
assert '-----BEGIN RSA PRIVATE KEY-----' in p.content
@ -84,8 +86,6 @@ class TestParameters(unittest.TestCase):
assert p.partition == 'Common'
@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
return_value=True)
class TestModuleManager(unittest.TestCase):
def setUp(self):
@ -101,14 +101,13 @@ class TestModuleManager(unittest.TestCase):
user='admin'
))
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=self.spec.argument_spec,
supports_check_mode=self.spec.supports_check_mode,
f5_product_name=self.spec.f5_product_name
supports_check_mode=self.spec.supports_check_mode
)
# Override methods in the specific type of manager
cm = ModuleManager(client)
cm = ModuleManager(module=module)
cm.exists = Mock(side_effect=[False, True])
cm.create_on_device = Mock(return_value=True)

Loading…
Cancel
Save