diff --git a/lib/ansible/modules/network/f5/bigip_pool.py b/lib/ansible/modules/network/f5/bigip_pool.py index 64746502485..0cd68705d53 100644 --- a/lib/ansible/modules/network/f5/bigip_pool.py +++ b/lib/ansible/modules/network/f5/bigip_pool.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py b/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py index 43c6b42d35c..3da33084fde 100644 --- a/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py +++ b/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_provision.py b/lib/ansible/modules/network/f5/bigip_provision.py index be9fc9d67e4..2a3cb350f54 100644 --- a/lib/ansible/modules/network/f5/bigip_provision.py +++ b/lib/ansible/modules/network/f5/bigip_provision.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_qkview.py b/lib/ansible/modules/network/f5/bigip_qkview.py index 05a6e3b2272..acce31c8c3e 100644 --- a/lib/ansible/modules/network/f5/bigip_qkview.py +++ b/lib/ansible/modules/network/f5/bigip_qkview.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_remote_syslog.py b/lib/ansible/modules/network/f5/bigip_remote_syslog.py index 0396b155601..6f8fcac4ecd 100644 --- a/lib/ansible/modules/network/f5/bigip_remote_syslog.py +++ b/lib/ansible/modules/network/f5/bigip_remote_syslog.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_security_port_list.py b/lib/ansible/modules/network/f5/bigip_security_port_list.py index c700864c26d..395d7688257 100644 --- a/lib/ansible/modules/network/f5/bigip_security_port_list.py +++ b/lib/ansible/modules/network/f5/bigip_security_port_list.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_selfip.py b/lib/ansible/modules/network/f5/bigip_selfip.py index 653fb4d10ad..8de9b1b600c 100644 --- a/lib/ansible/modules/network/f5/bigip_selfip.py +++ b/lib/ansible/modules/network/f5/bigip_selfip.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_snat_pool.py b/lib/ansible/modules/network/f5/bigip_snat_pool.py index d376449293a..c75cd16116c 100644 --- a/lib/ansible/modules/network/f5/bigip_snat_pool.py +++ b/lib/ansible/modules/network/f5/bigip_snat_pool.py @@ -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() diff --git a/lib/ansible/modules/network/f5/bigip_snmp.py b/lib/ansible/modules/network/f5/bigip_snmp.py index c9ef3953b7e..df877aff408 100644 --- a/lib/ansible/modules/network/f5/bigip_snmp.py +++ b/lib/ansible/modules/network/f5/bigip_snmp.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_snmp_trap.py b/lib/ansible/modules/network/f5/bigip_snmp_trap.py index e051f699315..1c683cb792f 100644 --- a/lib/ansible/modules/network/f5/bigip_snmp_trap.py +++ b/lib/ansible/modules/network/f5/bigip_snmp_trap.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_software_update.py b/lib/ansible/modules/network/f5/bigip_software_update.py index f6992f61b80..2655f1682e7 100644 --- a/lib/ansible/modules/network/f5/bigip_software_update.py +++ b/lib/ansible/modules/network/f5/bigip_software_update.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_ssl_certificate.py b/lib/ansible/modules/network/f5/bigip_ssl_certificate.py index 01148490f87..74f134166e6 100644 --- a/lib/ansible/modules/network/f5/bigip_ssl_certificate.py +++ b/lib/ansible/modules/network/f5/bigip_ssl_certificate.py @@ -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__': diff --git a/lib/ansible/modules/network/f5/bigip_ssl_key.py b/lib/ansible/modules/network/f5/bigip_ssl_key.py index 54bf0c50262..c6407b71394 100644 --- a/lib/ansible/modules/network/f5/bigip_ssl_key.py +++ b/lib/ansible/modules/network/f5/bigip_ssl_key.py @@ -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__': diff --git a/test/sanity/validate-modules/ignore.txt b/test/sanity/validate-modules/ignore.txt index 02f29069ef0..6412ac24f12 100644 --- a/test/sanity/validate-modules/ignore.txt +++ b/test/sanity/validate-modules/ignore.txt @@ -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 diff --git a/test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json b/test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json new file mode 100644 index 00000000000..bb77ca33e56 --- /dev/null +++ b/test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json @@ -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 + } +} diff --git a/test/units/modules/network/f5/test_bigip_pool.py b/test/units/modules/network/f5/test_bigip_pool.py index c1798520a09..5c69c09b503 100644 --- a/test/units/modules/network/f5/test_bigip_pool.py +++ b/test/units/modules/network/f5/test_bigip_pool.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_profile_client_ssl.py b/test/units/modules/network/f5/test_bigip_profile_client_ssl.py index 86e3e5f252f..29b30b45a32 100644 --- a/test/units/modules/network/f5/test_bigip_profile_client_ssl.py +++ b/test/units/modules/network/f5/test_bigip_profile_client_ssl.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_provision.py b/test/units/modules/network/f5/test_bigip_provision.py index b0e5321471f..8d99bf7f0d1 100644 --- a/test/units/modules/network/f5/test_bigip_provision.py +++ b/test/units/modules/network/f5/test_bigip_provision.py @@ -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() diff --git a/test/units/modules/network/f5/test_bigip_qkview.py b/test/units/modules/network/f5/test_bigip_qkview.py index 46b13ba76e6..ae452804391 100644 --- a/test/units/modules/network/f5/test_bigip_qkview.py +++ b/test/units/modules/network/f5/test_bigip_qkview.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_remote_syslog.py b/test/units/modules/network/f5/test_bigip_remote_syslog.py index ed455ab060e..4ea769d90d1 100644 --- a/test/units/modules/network/f5/test_bigip_remote_syslog.py +++ b/test/units/modules/network/f5/test_bigip_remote_syslog.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_security_port_list.py b/test/units/modules/network/f5/test_bigip_security_port_list.py index dbfac6789ec..b0265a76771 100644 --- a/test/units/modules/network/f5/test_bigip_security_port_list.py +++ b/test/units/modules/network/f5/test_bigip_security_port_list.py @@ -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]) diff --git a/test/units/modules/network/f5/test_bigip_selfip.py b/test/units/modules/network/f5/test_bigip_selfip.py index 6e74d71595b..2188b0f440b 100644 --- a/test/units/modules/network/f5/test_bigip_selfip.py +++ b/test/units/modules/network/f5/test_bigip_selfip.py @@ -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]) diff --git a/test/units/modules/network/f5/test_bigip_snat_pool.py b/test/units/modules/network/f5/test_bigip_snat_pool.py index 41e62a79564..d8f877b0b91 100644 --- a/test/units/modules/network/f5/test_bigip_snat_pool.py +++ b/test/units/modules/network/f5/test_bigip_snat_pool.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_snmp.py b/test/units/modules/network/f5/test_bigip_snmp.py index 6d5c5008226..0f1129e3cb9 100644 --- a/test/units/modules/network/f5/test_bigip_snmp.py +++ b/test/units/modules/network/f5/test_bigip_snmp.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_snmp_trap.py b/test/units/modules/network/f5/test_bigip_snmp_trap.py index de4a875a9d8..3948d944435 100644 --- a/test/units/modules/network/f5/test_bigip_snmp_trap.py +++ b/test/units/modules/network/f5/test_bigip_snmp_trap.py @@ -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( diff --git a/test/units/modules/network/f5/test_bigip_software_update.py b/test/units/modules/network/f5/test_bigip_software_update.py index 6256eae3b3b..04d7f3d68d0 100644 --- a/test/units/modules/network/f5/test_bigip_software_update.py +++ b/test/units/modules/network/f5/test_bigip_software_update.py @@ -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) diff --git a/test/units/modules/network/f5/test_bigip_ssl_certificate.py b/test/units/modules/network/f5/test_bigip_ssl_certificate.py index 950feeca713..036fc743463 100644 --- a/test/units/modules/network/f5/test_bigip_ssl_certificate.py +++ b/test/units/modules/network/f5/test_bigip_ssl_certificate.py @@ -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 diff --git a/test/units/modules/network/f5/test_bigip_ssl_key.py b/test/units/modules/network/f5/test_bigip_ssl_key.py index 2ee4eaa3ec1..f95eb5d812d 100644 --- a/test/units/modules/network/f5/test_bigip_ssl_key.py +++ b/test/units/modules/network/f5/test_bigip_ssl_key.py @@ -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)