diff --git a/lib/ansible/modules/network/f5/bigip_sys_db.py b/lib/ansible/modules/network/f5/bigip_sys_db.py index 53d06ace5eb..999ade412e5 100644 --- a/lib/ansible/modules/network/f5/bigip_sys_db.py +++ b/lib/ansible/modules/network/f5/bigip_sys_db.py @@ -30,7 +30,6 @@ options: that an existing variable is set to C(value). When C(reset) sets the variable back to the default value. At least one of value and state C(reset) are required. - required: False default: present choices: - present @@ -39,14 +38,9 @@ options: description: - The value to set the key to. At least one of value and state C(reset) are required. - required: False notes: - - Requires the f5-sdk Python package on the host. This is as easy as pip - install f5-sdk. - Requires BIG-IP version 12.0.0 or greater extends_documentation_fragment: f5 -requirements: - - f5-sdk author: - Tim Rupp (@caphrim007) ''' @@ -98,15 +92,37 @@ value: sample: false ''' -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError +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): @@ -124,16 +140,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 name(self): return self._values['key'] @@ -143,12 +149,17 @@ class Parameters(AnsibleF5Parameters): self._values['key'] = value +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 = {} @@ -159,10 +170,10 @@ class ModuleManager(object): if attr1 != attr2: changed[key] = attr1 if self.want.state == 'reset': - if str(self.want.value) == str(self.want.default_value): - changed[self.want.key] = self.want.value + if str(self.have.value) != str(self.have.default_value): + changed[self.want.key] = self.have.default_value if changed: - self.changes = Parameters(changed) + self.changes = Changes(params=changed) return True return False @@ -189,7 +200,7 @@ class ModuleManager(object): name=self.want.key ) result = resource.attrs - return Parameters(result) + return Parameters(params=result) def exists(self): resource = self.client.api.tm.sys.dbs.db.load( @@ -213,7 +224,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 @@ -235,9 +246,11 @@ 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() + self.reset_on_device() + self.want.update({'key': self.want.key}) + self.want.update({'value': self.have.default_value}) if self.exists(): return True else: @@ -249,13 +262,13 @@ class ModuleManager(object): resource = self.client.api.tm.sys.dbs.db.load( name=self.want.key ) - resource.update(value=self.want.default_value) + resource.update(value=self.have.default_value) class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( key=dict(required=True), state=dict( default='present', @@ -263,27 +276,30 @@ class ArgumentSpec(object): ), value=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_sys_global.py b/lib/ansible/modules/network/f5/bigip_sys_global.py index d5fcae780d2..e432b69faf8 100644 --- a/lib/ansible/modules/network/f5/bigip_sys_global.py +++ b/lib/ansible/modules/network/f5/bigip_sys_global.py @@ -30,48 +30,44 @@ options: gui_setup: description: - C(enable) or C(disabled) the Setup utility in the browser-based - Configuration utility - choices: ['yes', 'no'] + Configuration utility. + type: bool lcd_display: description: - Specifies, when C(enabled), that the system menu displays on the LCD screen on the front of the unit. This setting has no effect when used on the VE platform. - choices: ['yes', 'no'] + type: bool mgmt_dhcp: description: - Specifies whether or not to enable DHCP client on the management interface - choices: ['yes', 'no'] + type: bool net_reboot: description: - Specifies, when C(enabled), that the next time you reboot the system, the system boots to an ISO image on the network, rather than an internal media drive. - choices: ['yes', 'no'] + type: bool quiet_boot: description: - Specifies, when C(enabled), that the system suppresses informational text on the console during the boot cycle. When C(disabled), the system presents messages and informational text on the console during the boot cycle. - choices: ['yes', 'no'] + type: bool security_banner: description: - Specifies whether the system displays an advisory message on the login screen. - choices: ['yes', 'no'] + type: bool state: description: - The state of the variable on the system. When C(present), guarantees that an existing variable is set to C(value). - required: false default: present choices: - present -notes: - - Requires the f5-sdk Python package on the host. This is as easy as pip - install f5-sdk. extends_documentation_fragment: f5 requirements: - f5-sdk @@ -139,20 +135,40 @@ security_banner: sample: enabled ''' -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.parsing.convert_bool import BOOLEANS from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE -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): @@ -182,46 +198,6 @@ class Parameters(AnsibleF5Parameters): 'mgmt_dhcp', 'net_reboot', 'quiet_boot', 'console_timeout' ] - 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): pass @@ -323,9 +299,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() @@ -335,7 +312,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) @@ -351,7 +328,7 @@ class ModuleManager(object): else: changed[k] = change if changed: - self.changes = UsableChanges(changed) + self.changes = UsableChanges(params=changed) return True return False @@ -369,7 +346,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)) @@ -379,7 +356,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'] ) @@ -390,13 +367,13 @@ class ModuleManager(object): def read_current_from_device(self): resource = self.client.api.tm.sys.global_settings.load() result = resource.attrs - return ApiParameters(result) + return ApiParameters(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 @@ -412,7 +389,7 @@ class ArgumentSpec(object): self.supports_check_mode = True self.states = ['present'] self.on_off_choices = ['enabled', 'disabled', 'True', 'False'] + list(BOOLEANS) - self.argument_spec = dict( + argument_spec = dict( security_banner=dict( choices=self.on_off_choices ), @@ -435,39 +412,30 @@ class ArgumentSpec(object): console_timeout=dict(required=False, type='int', default=None), state=dict(default='present', choices=['present']) ) - self.f5_product_name = 'bigip' - - -def cleanup_tokens(client): - try: - resource = client.api.shared.authz.tokens_s.token.load( - name=client.api.icrs.token - ) - resource.delete() - except Exception: - pass + self.argument_spec = {} + self.argument_spec.update(f5_argument_spec) + self.argument_spec.update(argument_spec) def main(): - if not HAS_F5SDK: - raise F5ModuleError("The python f5-sdk module is required") - spec = ArgumentSpec() - client = AnsibleF5Client( + module = AnsibleModule( argument_spec=spec.argument_spec, - supports_check_mode=spec.supports_check_mode, - f5_product_name=spec.f5_product_name + supports_check_mode=spec.supports_check_mode ) + if not HAS_F5SDK: + module.fail_json(msg="The python f5-sdk module is required") try: - mm = ModuleManager(client) + client = F5Client(**module.params) + mm = ModuleManager(module=module, client=client) results = mm.exec_module() cleanup_tokens(client) - client.module.exit_json(**results) - except F5ModuleError as e: + module.exit_json(**results) + except F5ModuleError as ex: cleanup_tokens(client) - client.module.fail_json(msg=str(e)) + module.fail_json(msg=str(ex)) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/f5/bigip_traffic_group.py b/lib/ansible/modules/network/f5/bigip_traffic_group.py index 5c906550f00..89e9e6c7f00 100644 --- a/lib/ansible/modules/network/f5/bigip_traffic_group.py +++ b/lib/ansible/modules/network/f5/bigip_traffic_group.py @@ -24,11 +24,20 @@ options: description: - The name of the traffic group. required: True -notes: - - Requires the f5-sdk Python package on the host. This is as easy as - C(pip install f5-sdk). -requirements: - - f5-sdk >= 3.0.5 + partition: + description: + - Device partition to manage resources on. + default: Common + version_added: 2.5 + state: + description: + - When C(present), ensures that the traffic group exists. + - When C(absent), ensures the traffic group is removed. + default: present + choices: + - present + - absent + version_added: 2.5 extends_documentation_fragment: f5 author: - Tim Rupp (@caphrim007) @@ -49,18 +58,38 @@ RETURN = r''' # only common fields returned ''' +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import env_fallback -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError -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): @@ -80,36 +109,6 @@ class Parameters(AnsibleF5Parameters): ] - 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 = {} try: @@ -120,16 +119,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 - class Changes(Parameters): pass @@ -164,9 +153,10 @@ class Difference(object): class ModuleManager(object): - def __init__(self, client): - self.client = client - self.want = Parameters(self.client.module.params) + def __init__(self, *args, **kwargs): + self.module = kwargs.get('module', None) + self.client = kwargs.get('client', None) + self.want = Parameters(params=self.module.params) self.changes = Changes() def _set_changed_options(self): @@ -175,38 +165,9 @@ class ModuleManager(object): if getattr(self.want, key) is not None: changed[key] = getattr(self.want, key) if changed: - self.changes = Changes(changed) + self.changes = Changes(params=changed) def _update_changed_options(self): - """Sets the changed updatables when updating a resource - - A module needs to know what changed to determine whether to update - a resource (or set of resources). This method accomplishes this by - invoking the Difference engine code. - - Each parameter in the `Parameter` class' `updatables` array will be - given to the Difference engine's `compare` method. This is done in the - order the updatables are listed in the array. - - The `compare` method updates the `changes` dictionary if the following - way, - - * If `None` is returned, a change will not be registered. - * If a dictionary is returned, the `changes` dictionary will be updated - with the values in what was returned. - * Otherwise, the `changes` dictionary's key (the parameter being - compared) will be set to the value that is returned by `compare` - - The dictionary behavior is in place to allow you to change the key - that is set in the `changes` dictionary. There are frequently cases - where there is not a clean API map that can be set, nor a way to - otherwise allow you to change the attribute name of the resource being - updated before it is sent off to the remote device. Using a dictionary - return value of `compare` allows you to do this. - - Returns: - bool: True when changes are present. False otherwise. - """ diff = Difference(self.want, self.have) updatables = Parameters.updatables changed = dict() @@ -220,7 +181,7 @@ class ModuleManager(object): else: changed[k] = change if changed: - self.changes = Changes(changed) + self.changes = Changes(params=changed) return True return False @@ -252,7 +213,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'] ) @@ -274,13 +235,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(): @@ -293,7 +254,7 @@ class ModuleManager(object): raise F5ModuleError( "Traffic groups can only be created in the /Common partition" ) - if self.client.check_mode: + if self.module.check_mode: return True self.create_on_device() return True @@ -333,49 +294,44 @@ class ModuleManager(object): partition=self.want.partition ) result = resource.attrs - return Parameters(result) + return Parameters(params=result) class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( name=dict(required=True), - state=dict(default='present', 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 + state=dict(default='present', choices=['absent', 'present']), + 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") - 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_ucs.py b/lib/ansible/modules/network/f5/bigip_ucs.py index 568ace41530..b1a9268ad3a 100644 --- a/lib/ansible/modules/network/f5/bigip_ucs.py +++ b/lib/ansible/modules/network/f5/bigip_ucs.py @@ -87,8 +87,6 @@ options: - installed - present notes: - - Requires the f5-sdk Python package on the host. This is as easy as - pip install f5-sdk. - Only the most basic checks are performed by this module. Other checks and considerations need to be taken into account. See the following URL. https://support.f5.com/kb/en-us/solutions/public/11000/300/sol11318.html @@ -110,8 +108,6 @@ notes: - This module does not support restoring encrypted archives on replacement RMA units. extends_documentation_fragment: f5 -requirements: - - f5-sdk author: - Tim Rupp (@caphrim007) ''' @@ -182,28 +178,49 @@ RETURN = r''' import os import re -import sys import time -from distutils.version import LooseVersion -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import iteritems +from distutils.version import LooseVersion + +HAS_DEVEL_IMPORTS = False try: - from collections import OrderedDict + # 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 ordereddict import OrderedDict + from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: - pass + HAS_F5SDK = False try: - from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError + from collections import OrderedDict except ImportError: - HAS_F5SDK = False + try: + from ordereddict import OrderedDict + except ImportError: + pass class Parameters(AnsibleF5Parameters): @@ -292,14 +309,15 @@ class Parameters(AnsibleF5Parameters): class ModuleManager(object): - def __init__(self, client): - self.client = client + def __init__(self, *args, **kwargs): + self.client = kwargs.get('client', None) + self.kwargs = kwargs def exec_module(self): if self.is_version_v1(): - manager = V1Manager(self.client) + manager = V1Manager(**self.kwargs) else: - manager = V2Manager(self.client) + manager = V2Manager(**self.kwargs) return manager.exec_module() @@ -321,10 +339,10 @@ class ModuleManager(object): class BaseManager(object): - def __init__(self, client): - self.client = client - self.have = None - self.want = Parameters(self.client.module.params) + def __init__(self, *args, **kwargs): + self.module = kwargs.get('module', None) + self.client = kwargs.get('client', None) + self.want = Parameters(params=self.module.params) self.changes = Parameters() def exec_module(self): @@ -352,7 +370,7 @@ class BaseManager(object): return self.create() def update(self): - if self.client.check_mode: + if self.module.check_mode: if self.want.force: return True return False @@ -365,7 +383,7 @@ class BaseManager(object): return False def create(self): - if self.client.check_mode: + if self.module.check_mode: return True self.create_on_device() if not self.exists(): @@ -386,7 +404,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(): @@ -466,7 +484,6 @@ class V1Manager(BaseManager): * No API to upload UCS files """ - def create_on_device(self): remote_path = "/var/local/ucs" tpath_name = '/var/config/rest/downloads' @@ -563,7 +580,7 @@ class V2Manager(V1Manager): class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( force=dict( type='bool', default='no' @@ -585,30 +602,30 @@ class ArgumentSpec(object): ), ucs=dict(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") - - if sys.version_info < (2, 7): - raise F5ModuleError("F5 Ansible modules require Python >= 2.7") - 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_user.py b/lib/ansible/modules/network/f5/bigip_user.py index 7f257e20644..92d847ed503 100644 --- a/lib/ansible/modules/network/f5/bigip_user.py +++ b/lib/ansible/modules/network/f5/bigip_user.py @@ -74,13 +74,14 @@ options: choices: - always - on_create + 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. - Requires BIG-IP versions >= 12.0.0 extends_documentation_fragment: f5 -requirements: - - f5-sdk author: - Tim Rupp (@caphrim007) - Wojciech Wypior (@wojtek0806) @@ -191,23 +192,44 @@ shell: import re +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import env_fallback from distutils.version import LooseVersion -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 + +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 + # 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): @@ -228,36 +250,6 @@ class Parameters(AnsibleF5Parameters): 'shell', 'partitionAccess', 'description', 'name', 'password' ] - 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 - @property def partition_access(self): """Partition access values will require some transformation. @@ -324,18 +316,28 @@ 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_root_username_credential(): - manager = RootUserManager(self.client) + manager = self.get_manager('root') elif self.is_version_less_than_13(): - manager = UnparitionedManager(self.client) + manager = self.get_manager('v1') else: - manager = PartitionedManager(self.client) + manager = self.get_manager('v2') return manager.exec_module() + def get_manager(self, type): + if type == 'root': + return RootUserManager(**self.kwargs) + elif type == 'v1': + return UnparitionedManager(**self.kwargs) + elif type == 'v2': + return PartitionedManager(**self.kwargs) + def is_version_less_than_13(self): """Checks to see if the TMOS version is less than 13 @@ -351,17 +353,18 @@ class ModuleManager(object): return False def is_root_username_credential(self): - user = self.client.module.params.get('username_credential', None) + user = self.module.params.get('username_credential', None) if user == 'root': return True return False 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 - self.want = Parameters(self.client.module.params) + self.want = Parameters(params=self.module.params) self.changes = Parameters() def exec_module(self): @@ -388,7 +391,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 _update_changed_options(self): changed = {} @@ -411,7 +414,7 @@ class BaseManager(object): changed[key] = attr1 if changed: - self.changes = Parameters(changed) + self.changes = Parameters(params=changed) return True return False @@ -481,13 +484,13 @@ 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 def remove(self): - if self.client.check_mode: + if self.module.check_mode: return True self.remove_from_device() if self.exists(): @@ -499,7 +502,7 @@ class BaseManager(object): if self.want.shell == 'bash': self.validate_shell_parameter() self._set_changed_options() - if self.client.check_mode: + if self.module.check_mode: return True self.create_on_device() return True @@ -518,7 +521,7 @@ class UnparitionedManager(BaseManager): def read_current_from_device(self): tmp_res = self.client.api.tm.auth.users.user.load(name=self.want.name) result = tmp_res.attrs - return Parameters(result) + return Parameters(params=result) def exists(self): return self.client.api.tm.auth.users.user.exists(name=self.want.name) @@ -570,7 +573,7 @@ class PartitionedManager(BaseManager): def read_current_from_device(self): resource = self._read_one_resource_from_collection() result = resource.attrs - return Parameters(result) + return Parameters(params=result) def exists(self): collection = self.client.api.tm.auth.users.get_collection( @@ -646,7 +649,7 @@ class RootUserManager(BaseManager): class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( name=dict( required=True, aliases=['username_credential'] @@ -664,41 +667,37 @@ class ArgumentSpec(object): update_password=dict( default='always', choices=['always', 'on_create'] + ), + state=dict(default='present', choices=['absent', 'present']), + 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_vcmp_guest.py b/lib/ansible/modules/network/f5/bigip_vcmp_guest.py index edc6ca7c01d..59033c69635 100644 --- a/lib/ansible/modules/network/f5/bigip_vcmp_guest.py +++ b/lib/ansible/modules/network/f5/bigip_vcmp_guest.py @@ -112,9 +112,11 @@ options: - The number you can specify depends on the type of hardware you have. - In the event of a reboot, the system persists the guest to the same slot on which it ran prior to the reboot. + partition: + description: + - Device partition to manage resources on. + default: Common notes: - - Requires the f5-sdk Python package on the host. This is as easy as pip - install f5-sdk. - This module can take a lot of time to deploy vCMP guests. This is an intrinsic limitation of the vCMP system because it is booting real VMs on the BIG-IP device. This boot time is very similar in length to the time it takes to @@ -123,8 +125,6 @@ notes: means that it is not unusual for a vCMP host with many guests to take a long time (60+ minutes) to reboot and bring all the guests online. The BIG-IP chassis will be available before all vCMP guests are online. -requirements: - - f5-sdk >= 3.0.3 - netaddr extends_documentation_fragment: f5 author: @@ -173,16 +173,41 @@ vlans: sample: ['/Common/vlan1', '/Common/vlan2'] ''' +import time -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError -from ansible.module_utils.six import iteritems -from collections import defaultdict +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import env_fallback from collections import namedtuple -import time +HAS_DEVEL_IMPORTS = False + +try: + # Sideband repository used for dev + from library.module_utils.network.f5.bigip import HAS_F5SDK + from library.module_utils.network.f5.bigip import F5Client + from library.module_utils.network.f5.common import F5ModuleError + from library.module_utils.network.f5.common import AnsibleF5Parameters + from library.module_utils.network.f5.common import cleanup_tokens + from library.module_utils.network.f5.common import fqdn_name + from library.module_utils.network.f5.common import f5_argument_spec + try: + from library.module_utils.network.f5.common import iControlUnexpectedHTTPError + except ImportError: + HAS_F5SDK = False + HAS_DEVEL_IMPORTS = True +except ImportError: + # Upstream Ansible + from ansible.module_utils.network.f5.bigip import HAS_F5SDK + from ansible.module_utils.network.f5.bigip import F5Client + from ansible.module_utils.network.f5.common import F5ModuleError + from ansible.module_utils.network.f5.common import AnsibleF5Parameters + from ansible.module_utils.network.f5.common import cleanup_tokens + from ansible.module_utils.network.f5.common import fqdn_name + from ansible.module_utils.network.f5.common import f5_argument_spec + try: + from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError + except ImportError: + HAS_F5SDK = False try: from netaddr import IPAddress, AddrFormatError, IPNetwork @@ -192,7 +217,6 @@ except ImportError: try: from f5.utils.responses.handlers import Stats - from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False @@ -222,37 +246,6 @@ class Parameters(AnsibleF5Parameters): 'state' ] - def __init__(self, params=None, client=None): - self._values = defaultdict(lambda: None) - self._values['__warnings'] = [] - if params: - self.update(params=params) - self.client = client - - 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) @@ -268,16 +261,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 - @property def mgmt_route(self): if self._values['mgmt_route'] is None: @@ -394,9 +377,10 @@ class Difference(object): class ModuleManager(object): - def __init__(self, client): - self.client = client - self.want = Parameters(client=client, params=self.client.module.params) + def __init__(self, *args, **kwargs): + self.module = kwargs.get('module', None) + self.client = kwargs.get('client', None) + self.want = Parameters(client=self.client, params=self.module.params) self.changes = Changes() def _set_changed_options(self): @@ -405,7 +389,7 @@ class ModuleManager(object): if getattr(self.want, key) is not None: changed[key] = getattr(self.want, key) if changed: - self.changes = Changes(changed) + self.changes = Changes(params=changed) def _update_changed_options(self): diff = Difference(self.want, self.have) @@ -418,7 +402,7 @@ class ModuleManager(object): else: changed[k] = change if changed: - self.changes = Parameters(changed) + self.changes = Parameters(params=changed) return True return False @@ -450,7 +434,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'] ) @@ -476,7 +460,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() if self.want.state == 'provisioned': @@ -488,7 +472,7 @@ class ModuleManager(object): return True def remove(self): - if self.client.check_mode: + if self.module.check_mode: return True if self.want.delete_virtual_disk: self.have = self.read_current_from_device() @@ -501,7 +485,7 @@ class ModuleManager(object): def create(self): self._set_changed_options() - if self.client.check_mode: + if self.module.check_mode: return True if self.want.mgmt_tuple.subnet is None: self.want.update(dict( @@ -547,7 +531,7 @@ class ModuleManager(object): name=self.want.name ) result = resource.attrs - return Parameters(result) + return Parameters(params=result) def remove_virtual_disk(self): if self.virtual_disk_exists(): @@ -666,7 +650,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), vlans=dict(type='list'), mgmt_network=dict(choices=['bridged', 'isolated', 'host only']), @@ -680,47 +664,41 @@ class ArgumentSpec(object): delete_virtual_disk=dict( type='bool', default='no' ), - cores_per_slot=dict(type='int') + cores_per_slot=dict(type='int'), + 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) self.required_if = [ ['mgmt_network', 'bridged', ['mgmt_address']] ] -def cleanup_tokens(client): - try: - resource = client.api.shared.authz.tokens_s.token.load( - name=client.api.icrs.token - ) - resource.delete() - except Exception: - pass - - def main(): - if not HAS_F5SDK: - raise F5ModuleError("The python f5-sdk module is required") - - if not HAS_NETADDR: - raise F5ModuleError("The python netaddr module is required") - spec = ArgumentSpec() - client = AnsibleF5Client( + module = AnsibleModule( argument_spec=spec.argument_spec, - supports_check_mode=spec.supports_check_mode, - f5_product_name=spec.f5_product_name + 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_virtual_address.py b/lib/ansible/modules/network/f5/bigip_virtual_address.py index 1aed144b96d..9234dd5185f 100644 --- a/lib/ansible/modules/network/f5/bigip_virtual_address.py +++ b/lib/ansible/modules/network/f5/bigip_virtual_address.py @@ -100,14 +100,11 @@ options: - Specifies whether the system uses route advertisement for this virtual address. When disabled, the system does not advertise routes for this virtual address. - choices: - - yes - - no + type: bool partition: description: - Device partition to manage resources on. - required: False - default: 'Common' + default: Common version_added: 2.5 traffic_group: description: @@ -116,13 +113,10 @@ options: will be used. 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 - netaddr author: - Tim Rupp (@caphrim007) @@ -193,23 +187,46 @@ state: sample: disabled ''' -try: - import netaddr - HAS_NETADDR = True -except ImportError: - HAS_NETADDR = False - -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import env_fallback from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE +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: + import netaddr + HAS_NETADDR = True +except ImportError: + HAS_NETADDR = False class Parameters(AnsibleF5Parameters): @@ -349,17 +366,6 @@ class Parameters(AnsibleF5Parameters): result = self._filter_params(result) return result - def api_params(self): - result = {} - for api_attribute in self.api_attributes: - if 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 @@ -393,10 +399,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(client=self.client, params=self.module.params) self.changes = Changes() def _set_changed_options(self): @@ -405,7 +412,7 @@ class ModuleManager(object): if getattr(self.want, key) is not None: changed[key] = getattr(self.want, key) if changed: - self.changes = Changes(changed) + self.changes = Changes(params=changed) def _update_changed_options(self): diff = Difference(self.want, self.have) @@ -421,7 +428,7 @@ class ModuleManager(object): else: changed[k] = change if changed: - self.changes = Changes(changed) + self.changes = Changes(params=changed) return True return False @@ -467,7 +474,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.virtual_address_s.virtual_address.exists( @@ -481,18 +488,18 @@ class ModuleManager(object): if self.want.netmask is not None: if self.have.netmask != self.want.netmask: raise F5ModuleError( - "The netmask cannot be changed. Delete and recreate" + "The netmask cannot be changed. Delete and recreate " "the virtual address if you need to do this." ) if self.want.address is not None: if self.have.address != self.want.address: raise F5ModuleError( - "The address cannot be changed. Delete and recreate" + "The address cannot be changed. Delete and recreate " "the virtual address if you need to do this." ) 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 @@ -509,7 +516,7 @@ class ModuleManager(object): self._set_changed_options() if self.want.traffic_group is None: self.want.update({'traffic_group': '/Common/traffic-group-1'}) - if self.client.check_mode: + if self.module.check_mode: return True self.create_on_device() if self.exists(): @@ -527,7 +534,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(): @@ -545,7 +552,7 @@ class ModuleManager(object): class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( state=dict( default='present', choices=['present', 'absent', 'disabled', 'enabled'] @@ -577,29 +584,38 @@ class ArgumentSpec(object): use_route_advertisement=dict( type='bool' ), - traffic_group=dict() + traffic_group=dict(), + 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") + 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_virtual_server.py b/lib/ansible/modules/network/f5/bigip_virtual_server.py index 7d446233e18..ddccc9116fa 100644 --- a/lib/ansible/modules/network/f5/bigip_virtual_server.py +++ b/lib/ansible/modules/network/f5/bigip_virtual_server.py @@ -137,14 +137,6 @@ options: - Default Profile which manages the session persistence. - If you want to remove the existing default persistence profile, specify an empty value; C(""). See the documentation for an example. - route_advertisement_state: - description: - - Enable route advertisement for destination. - - Deprecated in 2.4. Use the C(bigip_virtual_address) module instead. - choices: - - enabled - - disabled - version_added: "2.3" description: description: - Virtual server description. @@ -171,12 +163,9 @@ options: version_added: 2.5 notes: - Requires BIG-IP software version >= 11 - - 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. requirements: - - f5-sdk - netaddr extends_documentation_fragment: f5 author: @@ -381,18 +370,38 @@ 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 from collections import namedtuple 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: import netaddr @@ -402,100 +411,6 @@ except ImportError: class Parameters(AnsibleF5Parameters): - def __init__(self, params=None): - self._values = defaultdict(lambda: None) - if params: - self.update(params=params) - - def update(self, params=None): - if params: - for k, v in iteritems(params): - if self.api_map is not None and k in self.api_map: - map_key = self.api_map[k] - else: - map_key = k - - # Handle weird API parameters like `dns.proxy.__iter__` by - # using a map provided by the module developer - class_attr = getattr(type(self), map_key, None) - if isinstance(class_attr, property): - # There is a mapped value for the api_map key - if class_attr.fset is None: - # If the mapped value does not have - # an associated setter - self._values[map_key] = v - else: - # The mapped value has a setter - setattr(self, map_key, v) - else: - # If the mapped value is not a @property - self._values[map_key] = v - - def to_return(self): - result = {} - for returnable in self.returnables: - try: - result[returnable] = getattr(self, returnable) - except Exception as ex: - pass - result = self._filter_params(result) - return result - - 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 VirtualAddressParameters(Parameters): - api_map = { - 'routeAdvertisement': 'route_advertisement_state' - } - returnables = [ - 'route_advertisement_state' - ] - - updatables = [ - 'route_advertisement_state' - ] - - api_attributes = [ - 'routeAdvertisement' - ] - - -class VirtualAddressModuleParameters(VirtualAddressParameters): - @property - def route_advertisement_state(self): - # TODO: Remove in 2.5 - if self._values['route_advertisement_state'] is None: - return None - if self._values['__warnings'] is None: - self._values['__warnings'] = [] - self._values['__warnings'].append( - dict( - msg="Usage of the 'route_advertisement_state' parameter is deprecated. Use the bigip_virtual_address module instead", - version='2.4' - ) - ) - return str(self._values['route_advertisement_state']) - - -class VirtualAddressApiParameters(VirtualAddressParameters): - pass - - -class VirtualServerParameters(Parameters): api_map = { 'sourceAddressTranslation': 'snat', 'fallbackPersistence': 'fallback_persistence_profile', @@ -566,12 +481,25 @@ class VirtualServerParameters(Parameters): 'vlans_disabled' ] - def __init__(self, params=None): - super(VirtualServerParameters, self).__init__(params) - self.profiles_mutex = [ - 'sip', 'sipsession', 'iiop', 'rtsp', 'http', 'diameter', - 'diametersession', 'radius', 'ftp', 'tftp', 'dns', 'pptp', 'fix' - ] + profiles_mutex = [ + 'sip', 'sipsession', 'iiop', 'rtsp', 'http', 'diameter', + 'diametersession', 'radius', 'ftp', 'tftp', 'dns', 'pptp', 'fix' + ] + + def to_return(self): + result = {} + for returnable in self.returnables: + try: + result[returnable] = getattr(self, returnable) + except Exception as ex: + pass + result = self._filter_params(result) + return result + + def _fqdn_name(self, value): + if value is not None and not value.startswith('/'): + return '/{0}/{1}'.format(self.partition, value) + return value def is_valid_ip(self, value): try: @@ -618,7 +546,7 @@ class VirtualServerParameters(Parameters): return result -class VirtualServerApiParameters(VirtualServerParameters): +class ApiParameters(Parameters): @property def destination(self): if self._values['destination'] is None: @@ -648,7 +576,7 @@ class VirtualServerApiParameters(VirtualServerParameters): if self._values['destination'] is None: result = Destination(ip=None, port=None, route_domain=None) return result - destination = re.sub(r'^/[a-zA-Z_.-]+/', '', self._values['destination']) + destination = re.sub(r'^/[a-zA-Z0-9_.-]+/', '', self._values['destination']) if self.is_valid_ip(destination): result = Destination( @@ -816,7 +744,7 @@ class VirtualServerApiParameters(VirtualServerParameters): return result -class VirtualServerModuleParameters(VirtualServerParameters): +class ModuleParameters(Parameters): def _handle_profile_context(self, tmp): if 'context' not in tmp: tmp['context'] = 'all' @@ -1106,7 +1034,11 @@ class VirtualServerModuleParameters(VirtualServerParameters): return result -class VirtualServerUsableChanges(VirtualServerParameters): +class Changes(Parameters): + pass + + +class UsableChanges(Changes): @property def vlans(self): if self._values['vlans'] is None: @@ -1118,11 +1050,7 @@ class VirtualServerUsableChanges(VirtualServerParameters): return self._values['vlans'] -class VirtualAddressUsableChanges(VirtualAddressParameters): - pass - - -class VirtualServerReportableChanges(VirtualServerParameters): +class ReportableChanges(Changes): @property def snat(self): if self._values['snat'] is None: @@ -1137,13 +1065,13 @@ class VirtualServerReportableChanges(VirtualServerParameters): @property def destination(self): - params = VirtualServerApiParameters(dict(destination=self._values['destination'])) + params = ApiParameters(params=dict(destination=self._values['destination'])) result = params.destination_tuple.ip return result @property def port(self): - params = VirtualServerApiParameters(dict(destination=self._values['destination'])) + params = ApiParameters(params=dict(destination=self._values['destination'])) result = params.destination_tuple.port return result @@ -1175,10 +1103,6 @@ class VirtualServerReportableChanges(VirtualServerParameters): return self._values['vlans'] -class VirtualAddressReportableChanges(VirtualAddressParameters): - pass - - class Difference(object): def __init__(self, want, have=None): self.have = have @@ -1461,49 +1385,12 @@ class Difference(object): class ModuleManager(object): - def __init__(self, client): - self.client = client - - def exec_module(self): - managers = list() - managers.append(self.get_manager('virtual_server')) - if self.client.module.params['route_advertisement_state'] is not None: - managers.append(self.get_manager('virtual_address')) - result = self.execute_managers(managers) - 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): - vsm = VirtualServerManager(self.client) - if type == 'virtual_server': - return vsm - elif type == 'virtual_address': - self.set_name_of_virtual_address() - result = VirtualAddressManager(self.client) - return result - - def set_name_of_virtual_address(self): - mgr = VirtualServerManager(self.client) - params = mgr.read_current_from_device() - destination = params.destination_tuple - self.client.module.params['name'] = destination.ip - - -class BaseManager(object): - 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.have = ApiParameters() + self.want = ModuleParameters(client=self.client, params=self.module.params) + self.changes = UsableChanges() def exec_module(self): changed = False @@ -1518,7 +1405,7 @@ class BaseManager(object): except iControlUnexpectedHTTPError as e: raise F5ModuleError(str(e)) - reportable = self.get_reportable_changes() + reportable = ReportableChanges(params=self.changes.to_return()) changes = reportable.to_return() result.update(**changes) result.update(dict(changed=changed)) @@ -1528,7 +1415,7 @@ class BaseManager(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'] ) @@ -1548,23 +1435,11 @@ 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 - def create(self): - if self.client.check_mode: - return True - - # This must be changed back to a list to make a valid REST API - # value. The module manipulates this as a normal dictionary - if self.want.default_persistence_profile is not None: - self.want.update({'default_persistence_profile': [self.want.default_persistence_profile]}) - - self.create_on_device() - return True - def should_update(self): result = self._update_changed_options() if result: @@ -1572,36 +1447,28 @@ 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(): raise F5ModuleError("Failed to delete the resource") return True - -class VirtualServerManager(BaseManager): - def __init__(self, client): - super(VirtualServerManager, self).__init__(client) - self.have = None - self.want = VirtualServerModuleParameters(self.client.module.params) - self.changes = VirtualServerUsableChanges() - def get_reportable_changes(self): - result = VirtualServerReportableChanges(self.changes.to_return()) + result = ReportableChanges(params=self.changes.to_return()) return result def _set_changed_options(self): changed = {} - for key in VirtualServerParameters.returnables: + for key in Parameters.returnables: if getattr(self.want, key) is not None: changed[key] = getattr(self.want, key) if changed: - self.changes = VirtualServerUsableChanges(changed) + self.changes = UsableChanges(params=changed) def _update_changed_options(self): diff = Difference(self.want, self.have) - updatables = VirtualServerParameters.updatables + updatables = Parameters.updatables changed = dict() for k in updatables: change = diff.compare(k) @@ -1613,7 +1480,7 @@ class VirtualServerManager(BaseManager): else: changed[k] = change if changed: - self.changes = VirtualServerUsableChanges(changed) + self.changes = UsableChanges(params=changed) return True return False @@ -1628,6 +1495,11 @@ class VirtualServerManager(BaseManager): required_resources = ['destination', 'port'] self._set_changed_options() + # This must be changed back to a list to make a valid REST API + # value. The module manipulates this as a normal dictionary + if self.want.default_persistence_profile is not None: + self.want.update({'default_persistence_profile': [self.want.default_persistence_profile]}) + if self.want.destination is None: raise F5ModuleError( "'destination' must be specified when creating a virtual server" @@ -1652,7 +1524,10 @@ class VirtualServerManager(BaseManager): raise F5ModuleError( "The source and destination addresses for the virtual server must be be the same type (IPv4 or IPv6)." ) - return super(VirtualServerManager, self).create() + if self.module.check_mode: + return True + self.create_on_device() + return True def update_on_device(self): params = self.changes.api_params() @@ -1674,7 +1549,7 @@ class VirtualServerManager(BaseManager): ) params = result.attrs params.update(dict(kind=result.to_dict().get('kind', None))) - result = VirtualServerApiParameters(params) + result = ApiParameters(params=params) return result def create_on_device(self): @@ -1694,71 +1569,10 @@ class VirtualServerManager(BaseManager): resource.delete() -class VirtualAddressManager(BaseManager): - def __init__(self, client): - super(VirtualAddressManager, self).__init__(client) - self.want = VirtualAddressModuleParameters(self.client.module.params) - self.have = VirtualAddressApiParameters() - self.changes = VirtualAddressUsableChanges() - - def get_reportable_changes(self): - result = VirtualAddressReportableChanges(self.changes.to_return()) - return result - - def _set_changed_options(self): - changed = {} - for key in VirtualAddressParameters.returnables: - if getattr(self.want, key) is not None: - changed[key] = getattr(self.want, key) - if changed: - self.changes = VirtualAddressUsableChanges(changed) - - def _update_changed_options(self): - diff = Difference(self.want, self.have) - updatables = VirtualAddressParameters.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 = VirtualAddressUsableChanges(changed) - return True - return False - - def read_current_from_device(self): - result = self.client.api.tm.ltm.virtual_address_s.virtual_address.load( - name=self.want.name, - partition=self.want.partition - ) - result = VirtualAddressParameters(result.attrs) - return result - - def update_on_device(self): - params = self.want.api_params() - resource = self.client.api.tm.ltm.virtual_address_s.virtual_address.load( - name=self.want.name, - partition=self.want.partition - ) - resource.modify(**params) - - def exists(self): - result = self.client.api.tm.ltm.virtual_address_s.virtual_address.exists( - name=self.want.name, - partition=self.want.partition - ) - return result - - class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( state=dict( default='present', choices=['present', 'absent', 'disabled', 'enabled'] @@ -1798,54 +1612,45 @@ class ArgumentSpec(object): pool=dict(), description=dict(), snat=dict(), - route_advertisement_state=dict( - choices=['enabled', 'disabled'] - ), default_persistence_profile=dict(), fallback_persistence_profile=dict(), source=dict(), - metadata=dict(type='raw') + metadata=dict(type='raw'), + 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) self.mutually_exclusive = [ ['enabled_vlans', 'disabled_vlans'] ] -def cleanup_tokens(client): - try: - resource = client.api.shared.authz.tokens_s.token.load( - name=client.api.icrs.token - ) - resource.delete() - except Exception: - pass - - def main(): - if not HAS_F5SDK: - raise F5ModuleError("The python f5-sdk module is required") - - if not HAS_NETADDR: - raise F5ModuleError("The python netaddr module is required") - spec = ArgumentSpec() - client = AnsibleF5Client( + module = AnsibleModule( argument_spec=spec.argument_spec, supports_check_mode=spec.supports_check_mode, - f5_product_name=spec.f5_product_name, mutually_exclusive=spec.mutually_exclusive ) + 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_vlan.py b/lib/ansible/modules/network/f5/bigip_vlan.py index 0f713397e6d..90b9ce8a705 100644 --- a/lib/ansible/modules/network/f5/bigip_vlan.py +++ b/lib/ansible/modules/network/f5/bigip_vlan.py @@ -55,13 +55,46 @@ options: - Tag number for the VLAN. The tag number can be any integer between 1 and 4094. The system automatically assigns a tag number if you do not specify a value. + mtu: + description: + - Specifies the maximum transmission unit (MTU) for traffic on this VLAN. + When creating a new VLAN, if this parameter is not specified, the default + value used will be C(1500). + - This number must be between 576 to 9198. + version_added: 2.5 + cmp_hash: + description: + - Specifies how the traffic on the VLAN will be disaggregated. The value + selected determines the traffic disaggregation method. You can choose to + disaggregate traffic based on C(source-address) (the source IP address), + C(destination-address) (destination IP address), or C(default), which + specifies that the default CMP hash uses L4 ports. + - When creating a new VLAN, if this parameter is not specified, the default + of C(default) is used. + version_added: 2.5 + dag_tunnel: + description: + - Specifies how the disaggregator (DAG) distributes received tunnel-encapsulated + packets to TMM instances. Select C(inner) to distribute packets based on information + in inner headers. Select C(outer) to distribute packets based on information in + outer headers without inspecting inner headers. + - When creating a new VLAN, if this parameter is not specified, the default + of C(outer) is used. + - This parameter is not supported on Virtual Editions of BIG-IP. + version_added: 2.5 + dag_round_robin: + description: + - Specifies whether some of the stateless traffic on the VLAN should be + disaggregated in a round-robin order instead of using a static hash. The + stateless traffic includes non-IP L2 traffic, ICMP, some UDP protocols, + and so on. + - When creating a new VLAN, if this parameter is not specified, the default + of (no) is used. + version_added: 2.5 + choices: [yes, no] notes: - - Requires the f5-sdk Python package on the host. This is as easy as pip - install f5-sdk. - Requires BIG-IP versions >= 12.0.0 extends_documentation_fragment: f5 -requirements: - - f5-sdk author: - Tim Rupp (@caphrim007) - Wojciech Wypior (@wojtek0806) @@ -114,162 +147,296 @@ EXAMPLES = r''' RETURN = r''' description: - description: The description set on the VLAN - returned: changed - type: string - sample: foo VLAN + description: The description set on the VLAN. + returned: changed + type: string + sample: foo VLAN interfaces: - description: Interfaces that the VLAN is assigned to - returned: changed - type: list - sample: ['1.1','1.2'] -name: - description: The name of the VLAN - returned: changed - type: string - sample: net1 + description: Interfaces that the VLAN is assigned to. + returned: changed + type: list + sample: ['1.1','1.2'] partition: - description: The partition that the VLAN was created on - returned: changed - type: string - sample: Common + description: The partition that the VLAN was created on. + returned: changed + type: string + sample: Common tag: - description: The ID of the VLAN - returned: changed - type: int - sample: 2345 + description: The ID of the VLAN. + returned: changed + type: int + sample: 2345 +cmp_hash: + description: New traffic disaggregation method. + returned: changed + type: string + sample: source-address +dag_tunnel: + description: The new DAG tunnel setting. + returned: changed + type: string + sample: outer ''' -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 try: - from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError + # Sideband repository used for dev + from library.module_utils.network.f5.bigip import HAS_F5SDK + from library.module_utils.network.f5.bigip import F5Client + from library.module_utils.network.f5.common import F5ModuleError + from library.module_utils.network.f5.common import AnsibleF5Parameters + from library.module_utils.network.f5.common import cleanup_tokens + from library.module_utils.network.f5.common import fqdn_name + from library.module_utils.network.f5.common import f5_argument_spec + try: + from library.module_utils.network.f5.common import iControlUnexpectedHTTPError + except ImportError: + HAS_F5SDK = False + HAS_DEVEL_IMPORTS = True except ImportError: - HAS_F5SDK = False + # Upstream Ansible + from ansible.module_utils.network.f5.bigip import HAS_F5SDK + from ansible.module_utils.network.f5.bigip import F5Client + from ansible.module_utils.network.f5.common import F5ModuleError + from ansible.module_utils.network.f5.common import AnsibleF5Parameters + from ansible.module_utils.network.f5.common import cleanup_tokens + from ansible.module_utils.network.f5.common import fqdn_name + from ansible.module_utils.network.f5.common import f5_argument_spec + try: + from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError + except ImportError: + HAS_F5SDK = False class Parameters(AnsibleF5Parameters): - def __init__(self, params=None): - self._values = defaultdict(lambda: None) - if params: - self.update(params=params) - - def update(self, params=None): - if params: - for k, v in iteritems(params): - if self.api_map is not None and k in self.api_map: - map_key = self.api_map[k] - else: - map_key = k - - # Handle weird API parameters like `dns.proxy.__iter__` by - # using a map provided by the module developer - class_attr = getattr(type(self), map_key, None) - if isinstance(class_attr, property): - # There is a mapped value for the api_map key - if class_attr.fset is None: - # If the mapped value does not have - # an associated setter - self._values[map_key] = v - else: - # The mapped value has a setter - setattr(self, map_key, v) - else: - # If the mapped value is not a @property - self._values[map_key] = v + api_map = { + 'cmpHash': 'cmp_hash', + 'dagTunnel': 'dag_tunnel', + 'dagRoundRobin': 'dag_round_robin' + } updatables = [ 'tagged_interfaces', 'untagged_interfaces', 'tag', - 'description' + 'description', 'mtu', 'cmp_hash', 'dag_tunnel', + 'dag_round_robin' ] returnables = [ - 'description', 'partition', 'name', 'tag', 'interfaces', - 'tagged_interfaces', 'untagged_interfaces' + 'description', 'partition', 'tag', 'interfaces', + 'tagged_interfaces', 'untagged_interfaces', 'mtu', + 'cmp_hash', 'dag_tunnel', 'dag_round_robin' ] api_attributes = [ - 'description', 'interfaces', 'partition', 'name', 'tag' + 'description', 'interfaces', 'tag', 'mtu', 'cmpHash', + 'dagTunnel', 'dagRoundRobin' ] - api_map = {} - @property - def interfaces(self): - tagged = self._values['tagged_interfaces'] - untagged = self._values['untagged_interfaces'] - if tagged: - return [dict(name=x, tagged=True) for x in tagged] - if untagged: - return [dict(name=x, untagged=True) for x in untagged] + def to_return(self): + result = {} + for returnable in self.returnables: + result[returnable] = getattr(self, returnable) + result = self._filter_params(result) + return result + +class ApiParameters(Parameters): @property def tagged_interfaces(self): - value = self._values['tagged_interfaces'] - if value is None: + if self._values['interfaces'] is None: + return None + result = [str(x.name) for x in self._values['interfaces'] if x.tagged is True] + result = sorted(result) + return result + + @property + def untagged_interfaces(self): + if self._values['interfaces'] is None: return None - ifcs = self._parse_return_ifcs() - for ifc in value: - if ifc not in ifcs: - err = 'The specified interface "%s" was not found' % ifc - raise F5ModuleError(err) - return value + result = [str(x.name) for x in self._values['interfaces'] if x.untagged is True] + result = sorted(result) + return result + +class ModuleParameters(Parameters): @property def untagged_interfaces(self): - value = self._values['untagged_interfaces'] - if value is None: + if self._values['untagged_interfaces'] is None: + return None + if self._values['untagged_interfaces'] is None: + return None + if len(self._values['untagged_interfaces']) == 1 and self._values['untagged_interfaces'][0] == '': + return '' + result = sorted([str(x) for x in self._values['untagged_interfaces']]) + return result + + @property + def tagged_interfaces(self): + if self._values['tagged_interfaces'] is None: + return None + if self._values['tagged_interfaces'] is None: return None - ifcs = self._parse_return_ifcs() - for ifc in value: - if ifc not in ifcs: - err = 'The specified interface "%s" was not found' % ifc - raise F5ModuleError(err) - return value - - def _get_interfaces_from_device(self): - lst = self.client.api.tm.net.interfaces.get_collection() - return lst - - def _parse_return_ifcs(self): - ifclst = self._get_interfaces_from_device() - ifcs = [str(x.name) for x in ifclst] - if not ifcs: - err = 'No interfaces were found' - raise F5ModuleError(err) - return ifcs + if len(self._values['tagged_interfaces']) == 1 and self._values['tagged_interfaces'][0] == '': + return '' + result = sorted([str(x) for x in self._values['tagged_interfaces']]) + return result + + @property + def mtu(self): + if self._values['mtu'] is None: + return None + if int(self._values['mtu']) < 576 or int(self._values['mtu']) > 9198: + raise F5ModuleError( + "The mtu value must be between 576 - 9198" + ) + return int(self._values['mtu']) + @property + def cmp_hash(self): + if self._values['cmp_hash'] is None: + return None + if self._values['cmp_hash'] in ['source-address', 'src', 'src-ip', 'source']: + return 'src-ip' + if self._values['cmp_hash'] in ['destination-address', 'dest', 'dst-ip', 'destination', 'dst']: + return 'dst-ip' + else: + return 'default' + + @property + def dag_round_robin(self): + if self._values['dag_round_robin'] is None: + return None + if self._values['dag_round_robin'] is True: + return 'enabled' + else: + return 'disabled' + + +class Changes(Parameters): def to_return(self): result = {} - for returnable in self.returnables: - result[returnable] = getattr(self, returnable) - result = self._filter_params(result) + try: + for returnable in self.returnables: + result[returnable] = getattr(self, returnable) + result = self._filter_params(result) + except Exception: + pass return result - def api_params(self): - result = {} - for api_attribute in self.api_attributes: - if 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) + +class UsableChanges(Changes): + pass + + +class ReportableChanges(Changes): + @property + def tagged_interfaces(self): + if self._values['interfaces'] is None: + return None + result = [str(x['name']) for x in self._values['interfaces'] if 'tagged' in x and x['tagged'] is True] + result = sorted(result) + return result + + @property + def untagged_interfaces(self): + if self._values['interfaces'] is None: + return None + result = [str(x['name']) for x in self._values['interfaces'] if 'untagged' in x and x['untagged'] is True] + result = sorted(result) + return result + + +class Difference(object): + def __init__(self, want, have=None): + self.want = want + self.have = have + + def compare(self, param): + try: + result = getattr(self, param) + return result + except AttributeError: + return self.__default(param) + + 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 untagged_interfaces(self): + result = [] + if self.want.untagged_interfaces is None: + return None + elif self.want.untagged_interfaces == '' and self.have.untagged_interfaces is None: + return None + elif self.want.untagged_interfaces == '' and len(self.have.untagged_interfaces) > 0: + pass + elif not self.have.untagged_interfaces: + result = dict( + interfaces=[dict(name=x, untagged=True) for x in self.want.untagged_interfaces] + ) + elif set(self.want.untagged_interfaces) != set(self.have.untagged_interfaces): + result = dict( + interfaces=[dict(name=x, untagged=True) for x in self.want.untagged_interfaces] + ) + else: + return None + return result + + @property + def tagged_interfaces(self): + result = [] + if self.want.tagged_interfaces is None: + return None + elif self.want.tagged_interfaces == '' and self.have.tagged_interfaces is None: + return None + elif self.want.tagged_interfaces == '' and len(self.have.tagged_interfaces) > 0: + pass + elif not self.have.tagged_interfaces: + result = dict( + interfaces=[dict(name=x, tagged=True) for x in self.want.tagged_interfaces] + ) + elif set(self.want.tagged_interfaces) != set(self.have.tagged_interfaces): + result = dict( + interfaces=[dict(name=x, tagged=True) for x in self.want.tagged_interfaces] + ) + else: + return None return result class ModuleManager(object): - def __init__(self, client): - self.client = client - self.have = None - self.want = Parameters() - self.want.client = self.client - self.want.update(self.client.module.params) - self.changes = Parameters() + 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 _update_changed_options(self): + 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 exec_module(self): changed = False @@ -284,39 +451,20 @@ class ModuleManager(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(result) return result - def _set_changed_options(self): - changed = {} - for key in Parameters.returnables: - if getattr(self.want, key) is not None: - changed[key] = getattr(self.want, key) - if changed: - self.changes = Parameters(changed) - - def _update_changed_options(self): - changed = {} - for key in Parameters.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 changed: - self.changes = Parameters(changed) - return True - return False - - def _have_interfaces(self, ifcs): - untagged = [str(x.name) for x in ifcs if hasattr(x, 'untagged')] - tagged = [str(x.name) for x in ifcs if hasattr(x, 'tagged')] - if untagged: - self.have.update({'untagged_interfaces': untagged}) - if tagged: - self.have.update({'tagged_interfaces': tagged}) + def _announce_deprecations(self, result): + warnings = result.pop('__warnings', []) + for warning in warnings: + self.module.deprecate( + msg=warning['msg'], + version=warning['version'] + ) def present(self): if self.exists(): @@ -336,18 +484,16 @@ class ModuleManager(object): return False def update(self): - self.have, ifcs = self.read_current_from_device() - if ifcs: - self._have_interfaces(ifcs) + 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(): @@ -355,49 +501,59 @@ class ModuleManager(object): return True def create(self): - self._set_changed_options() - if self.client.check_mode: + self.have = ApiParameters() + if self.want.mtu is None: + self.want.update({'mtu': 1500}) + self._update_changed_options() + if self.module.check_mode: return True self.create_on_device() return True def create_on_device(self): - params = self.want.api_params() - self.client.api.tm.net.vlans.vlan.create(**params) + params = self.changes.api_params() + self.client.api.tm.net.vlans.vlan.create( + name=self.want.name, + partition=self.want.partition, + **params + ) def update_on_device(self): - params = self.want.api_params() - result = self.client.api.tm.net.vlans.vlan.load( - name=self.want.name, partition=self.want.partition + params = self.changes.api_params() + resource = self.client.api.tm.net.vlans.vlan.load( + name=self.want.name, + partition=self.want.partition ) - result.modify(**params) + resource.modify(**params) def exists(self): return self.client.api.tm.net.vlans.vlan.exists( - name=self.want.name, partition=self.want.partition + name=self.want.name, + partition=self.want.partition ) def remove_from_device(self): - result = self.client.api.tm.net.vlans.vlan.load( - name=self.want.name, partition=self.want.partition + resource = self.client.api.tm.net.vlans.vlan.load( + name=self.want.name, + partition=self.want.partition ) - if result: - result.delete() + if resource: + resource.delete() def read_current_from_device(self): - tmp_res = self.client.api.tm.net.vlans.vlan.load( + resource = self.client.api.tm.net.vlans.vlan.load( name=self.want.name, partition=self.want.partition ) - ifcs = tmp_res.interfaces_s.get_collection() - - result = tmp_res.attrs - return Parameters(result), ifcs + interfaces = resource.interfaces_s.get_collection() + result = resource.attrs + result['interfaces'] = interfaces + 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, ), @@ -412,32 +568,56 @@ class ArgumentSpec(object): description=dict(), tag=dict( type='int' + ), + mtu=dict(type='int'), + cmp_hash=dict( + choices=[ + 'default', + 'destination-address', 'dest', 'dst-ip', 'destination', 'dst', + 'source-address', 'src', 'src-ip', 'source' + ] + ), + dag_tunnel=dict( + choices=['inner', 'outer'] + ), + dag_round_robin=dict(type='bool'), + 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) + self.mutually_exclusive = [ + ['tagged_interfaces', 'untagged_interfaces'] + ] def main(): - if not HAS_F5SDK: - raise F5ModuleError("The python f5-sdk module is required") - spec = ArgumentSpec() - client = AnsibleF5Client( + module = AnsibleModule( argument_spec=spec.argument_spec, supports_check_mode=spec.supports_check_mode, - f5_product_name=spec.f5_product_name, - mutually_exclusive=[ - ['tagged_interfaces', 'untagged_interfaces'] - ] + 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) + cleanup_tokens(client) + module.exit_json(**results) except F5ModuleError as e: - client.module.fail_json(msg=str(e)) + cleanup_tokens(client) + module.fail_json(msg=str(e)) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/f5/bigip_wait.py b/lib/ansible/modules/network/f5/bigip_wait.py index 525692b44d9..fb1e731346f 100644 --- a/lib/ansible/modules/network/f5/bigip_wait.py +++ b/lib/ansible/modules/network/f5/bigip_wait.py @@ -40,11 +40,6 @@ options: msg: description: - This overrides the normal error message from a failure to meet the required conditions. -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) @@ -84,133 +79,50 @@ import signal import time from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError -from ansible.module_utils.f5_utils import F5_COMMON_ARGS -from ansible.module_utils.six import iteritems -from collections import defaultdict + +HAS_DEVEL_IMPORTS = False try: - from f5.bigip import ManagementRoot as BigIpMgmt - 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 -def hard_timeout(client, want, start): +def hard_timeout(module, want, start): elapsed = datetime.datetime.utcnow() - start - client.module.fail_json( + module.fail_json( want.msg or "Timeout when waiting for BIG-IP", elapsed=elapsed.seconds ) -class AnsibleF5ClientStub(AnsibleF5Client): - """Interim class to disconnect Params from connection - - This module is an interim class that was made to separate the Ansible Module - Parameters from the connection to BIG-IP. - - Since this module needs to be able to control the connection process, the default - class is not appropriate. Therefore, we overload it and re-define out the - connection related work to a separate method. - - This class should serve as a reason to break apart this work itself into separate - classes in module_utils. There will be on-going work to do this and, when done, - the result will replace this work here. - - """ - def __init__(self, argument_spec=None, supports_check_mode=False, - mutually_exclusive=None, required_together=None, - required_if=None, required_one_of=None, add_file_common_args=False, - f5_product_name='bigip'): - self.f5_product_name = f5_product_name - - merged_arg_spec = dict() - merged_arg_spec.update(F5_COMMON_ARGS) - if argument_spec: - merged_arg_spec.update(argument_spec) - self.arg_spec = merged_arg_spec - - mutually_exclusive_params = [] - if mutually_exclusive: - mutually_exclusive_params += mutually_exclusive - - required_together_params = [] - if required_together: - required_together_params += required_together - - self.module = AnsibleModule( - argument_spec=merged_arg_spec, - supports_check_mode=supports_check_mode, - mutually_exclusive=mutually_exclusive_params, - required_together=required_together_params, - required_if=required_if, - required_one_of=required_one_of, - add_file_common_args=add_file_common_args - ) - - self.check_mode = self.module.check_mode - self._connect_params = self._get_connect_params() - - def connect(self): - try: - if 'transport' not in self.module.params or self.module.params['transport'] != 'cli': - self.api = self._get_mgmt_root( - self.f5_product_name, **self._connect_params - ) - return True - except Exception: - return False - - def _get_mgmt_root(self, type, **kwargs): - if type == 'bigip': - result = BigIpMgmt( - kwargs['server'], - kwargs['user'], - kwargs['password'], - port=kwargs['server_port'], - timeout=1, - token='tmos' - ) - return result - - class Parameters(AnsibleF5Parameters): returnables = [ 'elapsed' ] - 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 - def to_return(self): result = {} try: @@ -245,10 +157,11 @@ class Changes(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.have = None - self.want = Parameters(self.client.module.params) + self.want = Parameters(params=self.module.params) self.changes = Parameters() def exec_module(self): @@ -268,7 +181,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'] ) @@ -276,7 +189,7 @@ class ModuleManager(object): def execute(self): signal.signal( signal.SIGALRM, - lambda sig, frame: hard_timeout(self.client, self.want, start) + lambda sig, frame: hard_timeout(self.module, self.want, start) ) # setup handler before scheduling signal, to eliminate a race @@ -291,8 +204,8 @@ class ModuleManager(object): try: # The first test verifies that the REST API is available; this is done # by repeatedly trying to login to it. - connected = self._connect_to_device() - if not connected: + self.client = F5Client(**self.module.params) + if not self.client: continue if self._device_is_rebooting(): @@ -333,17 +246,13 @@ class ModuleManager(object): continue else: elapsed = datetime.datetime.utcnow() - start - self.client.module.fail_json( + self.module.fail_json( msg=self.want.msg or "Timeout when waiting for BIG-IP", elapsed=elapsed.seconds ) elapsed = datetime.datetime.utcnow() - start self.changes.update({'elapsed': elapsed.seconds}) return False - def _connect_to_device(self): - result = self.client.connect() - return result - def _device_is_rebooting(self): output = self.client.api.tm.util.bash.exec_cmd( 'run', @@ -386,45 +295,33 @@ class ModuleManager(object): class ArgumentSpec(object): def __init__(self): self.supports_check_mode = True - self.argument_spec = dict( + argument_spec = dict( timeout=dict(default=7200, type='int'), delay=dict(default=0, type='int'), sleep=dict(default=1, type='int'), msg=dict() ) - 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 = AnsibleF5ClientStub( + 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) + mm = ModuleManager(module=module) results = mm.exec_module() - cleanup_tokens(client) - client.module.exit_json(**results) + module.exit_json(**results) except F5ModuleError as e: - cleanup_tokens(client) - client.module.fail_json(msg=str(e)) + module.fail_json(msg=str(e)) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/f5/bigiq_regkey_license.py b/lib/ansible/modules/network/f5/bigiq_regkey_license.py index 6d9a17599df..8d312f2d4b2 100644 --- a/lib/ansible/modules/network/f5/bigiq_regkey_license.py +++ b/lib/ansible/modules/network/f5/bigiq_regkey_license.py @@ -89,17 +89,37 @@ description: import time -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError -from ansible.module_utils.six import iteritems -from collections import defaultdict +from ansible.module_utils.basic import AnsibleModule + +HAS_DEVEL_IMPORTS = False try: - from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError + # Sideband repository used for dev + from library.module_utils.network.f5.bigiq import HAS_F5SDK + from library.module_utils.network.f5.bigiq 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.bigiq import HAS_F5SDK + from ansible.module_utils.network.f5.bigiq 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): @@ -119,36 +139,6 @@ class Parameters(AnsibleF5Parameters): 'description' ] - 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 = {} try: @@ -159,16 +149,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 - class ApiParameters(Parameters): pass @@ -230,10 +210,10 @@ class Difference(object): class ModuleManager(object): - def __init__(self, client): - self.client = client - self.want = ModuleParameters(params=self.client.module.params) - self.want.update(dict(client=client)) + def __init__(self, *args, **kwargs): + self.module = kwargs.get('module', None) + self.client = kwargs.get('client', None) + self.want = ModuleParameters(client=self.client, params=self.module.params) self.have = ApiParameters() self.changes = UsableChanges() @@ -243,7 +223,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) @@ -259,7 +239,7 @@ class ModuleManager(object): else: changed[k] = change if changed: - self.changes = UsableChanges(changed) + self.changes = UsableChanges(params=changed) return True return False @@ -282,7 +262,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)) @@ -292,7 +272,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'] ) @@ -316,13 +296,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(): @@ -331,7 +311,7 @@ class ModuleManager(object): def create(self): self._set_changed_options() - if self.client.check_mode: + if self.module.check_mode: return True if self.want.accept_eula is False: raise F5ModuleError( @@ -401,42 +381,48 @@ class ModuleManager(object): if resource is None: return False 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( regkey_pool=dict(required=True), license_key=dict(required=True, no_log=True), description=dict(), - accept_eula=dict(type='bool') + accept_eula=dict(type='bool'), + state=dict( + default='present', + choices=['present', 'absent'] + ), ) - self.f5_product_name = 'bigiq' + self.argument_spec = {} + self.argument_spec.update(f5_argument_spec) + self.argument_spec.update(argument_spec) self.required_if = [ ['state', 'present', ['accept_eula']] ] def main(): - if not HAS_F5SDK: - raise F5ModuleError("The python f5-sdk module is required") - spec = ArgumentSpec() - client = AnsibleF5Client( + module = AnsibleModule( argument_spec=spec.argument_spec, supports_check_mode=spec.supports_check_mode, - f5_product_name=spec.f5_product_name + required_if=spec.required_if ) + 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) + module.exit_json(**results) except F5ModuleError as e: - client.module.fail_json(msg=str(e)) + module.fail_json(msg=str(e)) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/f5/bigiq_regkey_pool.py b/lib/ansible/modules/network/f5/bigiq_regkey_pool.py index 635fc55cb35..07c79243abb 100644 --- a/lib/ansible/modules/network/f5/bigiq_regkey_pool.py +++ b/lib/ansible/modules/network/f5/bigiq_regkey_pool.py @@ -69,18 +69,37 @@ description: sample: My description ''' +from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.f5_utils import AnsibleF5Client -from ansible.module_utils.f5_utils import AnsibleF5Parameters -from ansible.module_utils.f5_utils import HAS_F5SDK -from ansible.module_utils.f5_utils import F5ModuleError -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.bigiq import HAS_F5SDK + from library.module_utils.network.f5.bigiq 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.bigiq import HAS_F5SDK + from ansible.module_utils.network.f5.bigiq 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): @@ -100,36 +119,6 @@ class Parameters(AnsibleF5Parameters): 'description' ] - 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 = {} try: @@ -140,16 +129,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 - class ModuleParameters(Parameters): @property @@ -214,10 +193,10 @@ class Difference(object): class ModuleManager(object): - def __init__(self, client): - self.client = client - self.want = ModuleParameters(self.client.module.params) - self.want.update({'client': client}) + def __init__(self, *args, **kwargs): + self.module = kwargs.get('module', None) + self.client = kwargs.get('client', None) + self.want = ModuleParameters(client=self.client, params=self.module.params) self.have = ApiParameters() self.changes = UsableChanges() @@ -227,7 +206,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) @@ -243,7 +222,7 @@ class ModuleManager(object): else: changed[k] = change if changed: - self.changes = Changes(changed) + self.changes = Changes(params=changed) return True return False @@ -266,7 +245,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)) @@ -276,7 +255,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'] ) @@ -297,13 +276,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(): @@ -312,7 +291,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 @@ -348,13 +327,13 @@ class ModuleManager(object): id=self.want.uuid ) 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(), state=dict( @@ -362,27 +341,28 @@ class ArgumentSpec(object): choices=['absent', 'present'] ) ) - self.f5_product_name = 'bigiq' + 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) + module.exit_json(**results) except F5ModuleError as e: - client.module.fail_json(msg=str(e)) + module.fail_json(msg=str(e)) if __name__ == '__main__': diff --git a/test/sanity/validate-modules/ignore.txt b/test/sanity/validate-modules/ignore.txt index 6412ac24f12..934a2a0b4aa 100644 --- a/test/sanity/validate-modules/ignore.txt +++ b/test/sanity/validate-modules/ignore.txt @@ -41,18 +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_sys_db.py E321 -lib/ansible/modules/network/f5/bigip_sys_global.py E321 -lib/ansible/modules/network/f5/bigip_traffic_group.py E321 -lib/ansible/modules/network/f5/bigip_ucs.py E321 -lib/ansible/modules/network/f5/bigip_user.py E321 -lib/ansible/modules/network/f5/bigip_vcmp_guest.py E321 -lib/ansible/modules/network/f5/bigip_virtual_address.py E321 -lib/ansible/modules/network/f5/bigip_virtual_server.py E321 -lib/ansible/modules/network/f5/bigip_vlan.py E321 -lib/ansible/modules/network/f5/bigip_wait.py E321 -lib/ansible/modules/network/f5/bigiq_regkey_license.py E321 -lib/ansible/modules/network/f5/bigiq_regkey_pool.py E321 lib/ansible/modules/network/illumos/dladm_linkprop.py E317 lib/ansible/modules/network/illumos/ipadm_addrprop.py E317 lib/ansible/modules/network/illumos/ipadm_ifprop.py E317 diff --git a/test/units/modules/network/f5/fixtures/load_vlan_interfaces.json b/test/units/modules/network/f5/fixtures/load_vlan_interfaces.json new file mode 100644 index 00000000000..9fa16f76b2c --- /dev/null +++ b/test/units/modules/network/f5/fixtures/load_vlan_interfaces.json @@ -0,0 +1,15 @@ +{ + "kind": "tm:net:vlan:interfaces:interfacescollectionstate", + "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~vlan1/interfaces?ver=13.0.0", + "items": [ + { + "kind": "tm:net:vlan:interfaces:interfacesstate", + "name": "1.2", + "fullPath": "1.2", + "generation": 105, + "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~vlan1/interfaces/1.2?ver=13.0.0", + "tagMode": "none", + "tagged": true + } + ] +} diff --git a/test/units/modules/network/f5/test_bigip_sys_db.py b/test/units/modules/network/f5/test_bigip_sys_db.py index 1d9ee35b7f2..3d8e9baa3c7 100644 --- a/test/units/modules/network/f5/test_bigip_sys_db.py +++ b/test/units/modules/network/f5/test_bigip_sys_db.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_sys_db import Parameters from library.bigip_sys_db import ModuleManager from library.bigip_sys_db 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_sys_db import Parameters from ansible.modules.network.f5.bigip_sys_db import ModuleManager from ansible.modules.network.f5.bigip_sys_db 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") @@ -66,7 +68,7 @@ class TestParameters(unittest.TestCase): server='localhost', user='admin' ) - p = Parameters(args) + p = Parameters(params=args) assert p.key == 'foo' assert p.value == 'bar' @@ -80,13 +82,11 @@ class TestParameters(unittest.TestCase): user='admin' ) - p = Parameters(args) + p = Parameters(params=args) assert p.key == 'foo' assert p.value == 'bar' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -118,12 +118,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.exists = Mock(return_value=False) diff --git a/test/units/modules/network/f5/test_bigip_sys_global.py b/test/units/modules/network/f5/test_bigip_sys_global.py index 18a71c1c51d..aa6f540a19a 100644 --- a/test/units/modules/network/f5/test_bigip_sys_global.py +++ b/test/units/modules/network/f5/test_bigip_sys_global.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_sys_global import ApiParameters from library.bigip_sys_global import ModuleParameters from library.bigip_sys_global import ModuleManager from library.bigip_sys_global 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_sys_global import ModuleParameters from ansible.modules.network.f5.bigip_sys_global import ModuleManager from ansible.modules.network.f5.bigip_sys_global 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") @@ -71,7 +73,7 @@ class TestParameters(unittest.TestCase): quiet_boot='yes', security_banner='yes', ) - p = ModuleParameters(args) + p = ModuleParameters(params=args) assert p.banner_text == 'this is a banner' assert p.console_timeout == 100 assert p.gui_setup == 'enabled' @@ -83,7 +85,7 @@ class TestParameters(unittest.TestCase): def test_api_parameters(self): args = load_fixture('load_sys_global_settings.json') - p = ApiParameters(args) + p = ApiParameters(params=args) assert 'Welcome to the BIG-IP Configuration Utility' in p.banner_text assert p.console_timeout == 0 assert p.gui_setup == 'disabled' @@ -94,8 +96,6 @@ class TestParameters(unittest.TestCase): assert p.security_banner == 'enabled' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -113,14 +113,13 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = ApiParameters(load_fixture('load_sys_global_settings.json')) + current = ApiParameters(params=load_fixture('load_sys_global_settings.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(return_value=False) diff --git a/test/units/modules/network/f5/test_bigip_traffic_group.py b/test/units/modules/network/f5/test_bigip_traffic_group.py index 83788845c5b..d068d51980f 100644 --- a/test/units/modules/network/f5/test_bigip_traffic_group.py +++ b/test/units/modules/network/f5/test_bigip_traffic_group.py @@ -18,21 +18,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.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule try: from library.bigip_traffic_group import Parameters from library.bigip_traffic_group import ModuleManager from library.bigip_traffic_group 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_traffic_group import Parameters from ansible.modules.network.f5.bigip_traffic_group import ModuleManager from ansible.modules.network.f5.bigip_traffic_group 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 +66,10 @@ class TestParameters(unittest.TestCase): name='foo' ) - p = Parameters(args) + p = Parameters(params=args) assert p.name == 'foo' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -84,13 +83,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_ucs.py b/test/units/modules/network/f5/test_bigip_ucs.py index 374b46c70e6..2298bebb932 100644 --- a/test/units/modules/network/f5/test_bigip_ucs.py +++ b/test/units/modules/network/f5/test_bigip_ucs.py @@ -18,8 +18,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.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule try: from library.bigip_ucs import Parameters @@ -27,7 +26,8 @@ try: from library.bigip_ucs import ArgumentSpec from library.bigip_ucs import V1Manager from library.bigip_ucs import V2Manager - 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: @@ -36,7 +36,8 @@ except ImportError: from ansible.modules.network.f5.bigip_ucs import ArgumentSpec from ansible.modules.network.f5.bigip_ucs import V1Manager from ansible.modules.network.f5.bigip_ucs import V2Manager - 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") @@ -76,7 +77,7 @@ class TestParameters(unittest.TestCase): state='installed' ) - p = Parameters(args) + p = Parameters(params=args) assert p.ucs == '/root/bigip.localhost.localdomain.ucs' assert p.force is True assert p.include_chassis_level_config is True @@ -98,7 +99,7 @@ class TestParameters(unittest.TestCase): reset_trust=False ) - p = Parameters(args) + p = Parameters(params=args) assert p.ucs == '/root/bigip.localhost.localdomain.ucs' assert p.include_chassis_level_config is False assert p.no_license is False @@ -107,8 +108,6 @@ class TestParameters(unittest.TestCase): assert p.install_command == "tmsh load sys ucs /var/local/ucs/bigip.localhost.localdomain.ucs" -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestV1Manager(unittest.TestCase): def setUp(self): @@ -122,17 +121,16 @@ class TestV1Manager(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_v1 = Mock(return_value=True) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.create_on_device = Mock(return_value=True) vm.exists = Mock(side_effect=[False, True]) @@ -149,17 +147,16 @@ class TestV1Manager(unittest.TestCase): state='present' )) - 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_v1 = Mock(return_value=True) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.create_on_device = Mock(return_value=True) vm.exists = Mock(side_effect=[False, True]) @@ -176,17 +173,16 @@ class TestV1Manager(unittest.TestCase): state='installed' )) - 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_v1 = Mock(return_value=True) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.create_on_device = Mock(return_value=True) vm.exists = Mock(return_value=True) vm.install_on_device = Mock(return_value=True) @@ -204,17 +200,16 @@ class TestV1Manager(unittest.TestCase): state='absent' )) - 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_v1 = Mock(return_value=True) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.remove_from_device = Mock(return_value=True) vm.exists = Mock(side_effect=[True, False]) @@ -231,17 +226,16 @@ class TestV1Manager(unittest.TestCase): state='absent' )) - 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_v1 = Mock(return_value=True) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.remove_from_device = Mock(return_value=True) vm.exists = Mock(side_effect=[True, True]) @@ -250,8 +244,6 @@ class TestV1Manager(unittest.TestCase): assert 'Failed to delete' in str(ex.value) -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestV2Manager(unittest.TestCase): def setUp(self): @@ -265,17 +257,16 @@ class TestV2Manager(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_v1 = Mock(return_value=False) - vm = V2Manager(client) + vm = V2Manager(module=module) vm.create_on_device = Mock(return_value=True) vm.exists = Mock(side_effect=[False, True]) @@ -292,17 +283,16 @@ class TestV2Manager(unittest.TestCase): state='present' )) - 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_v1 = Mock(return_value=False) - vm = V2Manager(client) + vm = V2Manager(module=module) vm.create_on_device = Mock(return_value=True) vm.exists = Mock(side_effect=[False, True]) @@ -319,17 +309,16 @@ class TestV2Manager(unittest.TestCase): state='installed' )) - 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_v1 = Mock(return_value=False) - vm = V2Manager(client) + vm = V2Manager(module=module) vm.create_on_device = Mock(return_value=True) vm.exists = Mock(return_value=True) vm.install_on_device = Mock(return_value=True) @@ -347,17 +336,16 @@ class TestV2Manager(unittest.TestCase): state='absent' )) - 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_v1 = Mock(return_value=False) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.remove_from_device = Mock(return_value=True) vm.exists = Mock(side_effect=[True, False]) @@ -374,17 +362,16 @@ class TestV2Manager(unittest.TestCase): state='absent' )) - 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_v1 = Mock(return_value=False) - vm = V1Manager(client) + vm = V1Manager(module=module) vm.remove_from_device = Mock(return_value=True) vm.exists = Mock(side_effect=[True, True]) diff --git a/test/units/modules/network/f5/test_bigip_user.py b/test/units/modules/network/f5/test_bigip_user.py index e504ac04595..3e53c019c08 100644 --- a/test/units/modules/network/f5/test_bigip_user.py +++ b/test/units/modules/network/f5/test_bigip_user.py @@ -18,8 +18,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.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule try: from library.bigip_user import Parameters @@ -27,7 +26,8 @@ try: from library.bigip_user import ArgumentSpec from library.bigip_user import UnparitionedManager from library.bigip_user import PartitionedManager - 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: @@ -36,7 +36,8 @@ except ImportError: from ansible.modules.network.f5.bigip_user import ArgumentSpec from ansible.modules.network.f5.bigip_user import UnparitionedManager from ansible.modules.network.f5.bigip_user import PartitionedManager - 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") @@ -74,7 +75,7 @@ class TestParameters(unittest.TestCase): update_password='always' ) - p = Parameters(args) + p = Parameters(params=args) assert p.username_credential == 'someuser' assert p.password_credential == 'testpass' assert p.full_name == 'Fake Person' @@ -91,7 +92,7 @@ class TestParameters(unittest.TestCase): shell='none' ) - p = Parameters(args) + p = Parameters(params=args) assert p.name == 'someuser' assert p.password == 'testpass' assert p.full_name == 'Fake Person' @@ -99,8 +100,6 @@ class TestParameters(unittest.TestCase): assert p.shell == 'none' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -118,21 +117,21 @@ class TestManager(unittest.TestCase): update_password='on_create' )) - 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.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.create_on_device = Mock(return_value=True) pm.exists = Mock(return_value=False) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is True assert results['partition_access'] == access @@ -147,21 +146,21 @@ 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.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.create_on_device = Mock(return_value=True) pm.exists = Mock(return_value=False) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is True assert results['partition_access'] == access @@ -177,26 +176,26 @@ 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.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.create_on_device = Mock(return_value=True) pm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + msg = "The 'update_password' option " \ "needs to be set to 'on_create' when creating " \ "a resource with a password." with pytest.raises(F5ModuleError) as ex: - pm.exec_module() + mm.exec_module() assert str(ex.value) == msg def test_create_user_partition_access_raises(self, *args): @@ -207,25 +206,25 @@ 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.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.create_on_device = Mock(return_value=True) pm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + msg = "The 'partition_access' option " \ "is required when creating a resource." with pytest.raises(F5ModuleError) as ex: - pm.exec_module() + mm.exec_module() assert str(ex.value) == msg def test_create_user_shell_bash(self, *args): @@ -241,21 +240,21 @@ class TestManager(unittest.TestCase): shell='bash' )) - 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.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.create_on_device = Mock(return_value=True) pm.exists = Mock(return_value=False) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is True assert results['partition_access'] == access @@ -273,25 +272,25 @@ class TestManager(unittest.TestCase): shell='bash' )) - 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.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.create_on_device = Mock(return_value=True) pm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + msg = "Shell access is only available to 'admin' or " \ "'resource-admin' roles" with pytest.raises(F5ModuleError) as ex: - pm.exec_module() + mm.exec_module() assert str(ex.value) == msg def test_update_user_password_no_pass(self, *args): @@ -303,26 +302,26 @@ 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 ) # Configure the parameters that would be returned by querying the # remote device - current = Parameters(load_fixture('load_auth_user_no_pass.json')) + current = Parameters(params=load_fixture('load_auth_user_no_pass.json')) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.exists = Mock(return_value=True) pm.update_on_device = Mock(return_value=True) pm.read_current_from_device = Mock(return_value=current) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is True @@ -335,26 +334,26 @@ 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 ) # Configure the parameters that would be returned by querying the # remote device - current = Parameters(load_fixture('load_auth_user_with_pass.json')) + current = Parameters(params=load_fixture('load_auth_user_with_pass.json')) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.exists = Mock(return_value=True) pm.update_on_device = Mock(return_value=True) pm.read_current_from_device = Mock(return_value=current) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is True @@ -367,31 +366,31 @@ class TestManager(unittest.TestCase): shell='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 ) # Configure the parameters that would be returned by querying the # remote device current = Parameters( - dict( + params=dict( user='admin', shell='tmsh' ) ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.exists = Mock(return_value=True) pm.update_on_device = Mock(return_value=True) pm.read_current_from_device = Mock(return_value=current) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is True assert results['shell'] == 'none' @@ -405,32 +404,32 @@ class TestManager(unittest.TestCase): shell='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 ) # Configure the parameters that would be returned by querying the # remote device access = [{'name': 'Common', 'role': 'guest'}] current = Parameters( - dict( + params=dict( user='admin', partition_access=access ) ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=False) - - pm = PartitionedManager(client) + pm = PartitionedManager(module=module, params=module.params) pm.exists = Mock(return_value=True) pm.update_on_device = Mock(return_value=True) pm.read_current_from_device = Mock(return_value=current) - results = pm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=False) + mm.get_manager = Mock(return_value=pm) + + results = mm.exec_module() assert results['changed'] is False assert not hasattr(results, 'shell') @@ -444,17 +443,16 @@ class TestManager(unittest.TestCase): shell='bash' )) - 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 ) # Configure the parameters that would be returned by querying the # remote device access = [{'name': 'all', 'role': 'admin'}] current = Parameters( - dict( + params=dict( user='admin', shell='tmsh', partition_access=access @@ -462,15 +460,16 @@ class TestManager(unittest.TestCase): ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True assert results['shell'] == 'bash' @@ -484,10 +483,9 @@ class TestManager(unittest.TestCase): shell='bash' )) - 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 ) # Configure the parameters that would be returned by querying the @@ -497,7 +495,7 @@ class TestManager(unittest.TestCase): {'name': 'all', 'role': 'guest'} ] current = Parameters( - dict( + params=dict( user='admin', shell='tmsh', partition_access=access @@ -505,24 +503,23 @@ class TestManager(unittest.TestCase): ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + msg = "Shell access is only available to 'admin' or " \ "'resource-admin' roles" with pytest.raises(F5ModuleError) as ex: - upm.exec_module() + mm.exec_module() assert str(ex.value) == msg -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestLegacyManager(unittest.TestCase): def setUp(self): @@ -540,21 +537,21 @@ class TestLegacyManager(unittest.TestCase): update_password='on_create' )) - 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.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.create_on_device = Mock(return_value=True) upm.exists = Mock(return_value=False) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True assert results['partition_access'] == access @@ -569,21 +566,21 @@ class TestLegacyManager(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.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.create_on_device = Mock(return_value=True) upm.exists = Mock(return_value=False) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True assert results['partition_access'] == access @@ -599,26 +596,26 @@ class TestLegacyManager(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.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.create_on_device = Mock(return_value=True) upm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + msg = "The 'update_password' option " \ "needs to be set to 'on_create' when creating " \ "a resource with a password." with pytest.raises(F5ModuleError) as ex: - upm.exec_module() + mm.exec_module() assert str(ex.value) == msg def test_create_user_partition_access_raises(self, *args): @@ -629,25 +626,25 @@ class TestLegacyManager(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.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.create_on_device = Mock(return_value=True) upm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + msg = "The 'partition_access' option " \ "is required when creating a resource." with pytest.raises(F5ModuleError) as ex: - upm.exec_module() + mm.exec_module() assert str(ex.value) == msg def test_create_user_shell_bash(self, *args): @@ -663,21 +660,21 @@ class TestLegacyManager(unittest.TestCase): shell='bash' )) - 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.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.create_on_device = Mock(return_value=True) upm.exists = Mock(return_value=False) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True assert results['partition_access'] == access @@ -695,25 +692,25 @@ class TestLegacyManager(unittest.TestCase): shell='bash' )) - 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.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.create_on_device = Mock(return_value=True) upm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + msg = "Shell access is only available to 'admin' or " \ "'resource-admin' roles" with pytest.raises(F5ModuleError) as ex: - upm.exec_module() + mm.exec_module() assert str(ex.value) == msg def test_update_user_password(self, *args): @@ -725,32 +722,32 @@ class TestLegacyManager(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 ) # Configure the parameters that would be returned by querying the # remote device access = [{'name': 'Common', 'role': 'guest'}] current = Parameters( - dict( + params=dict( shell='tmsh', partition_access=access ) ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True @@ -763,31 +760,31 @@ class TestLegacyManager(unittest.TestCase): shell='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 ) # Configure the parameters that would be returned by querying the # remote device current = Parameters( - dict( + params=dict( user='admin', shell='tmsh' ) ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True assert results['shell'] == 'none' @@ -801,32 +798,32 @@ class TestLegacyManager(unittest.TestCase): shell='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 ) # Configure the parameters that would be returned by querying the # remote device access = [{'name': 'Common', 'role': 'guest'}] current = Parameters( - dict( + params=dict( user='admin', partition_access=access ) ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is False assert not hasattr(results, 'shell') @@ -840,17 +837,16 @@ class TestLegacyManager(unittest.TestCase): shell='bash' )) - 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 ) # Configure the parameters that would be returned by querying the # remote device access = [{'name': 'all', 'role': 'admin'}] current = Parameters( - dict( + params=dict( user='admin', shell='tmsh', partition_access=access @@ -858,15 +854,16 @@ class TestLegacyManager(unittest.TestCase): ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) - results = upm.exec_module() + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + + results = mm.exec_module() assert results['changed'] is True assert results['shell'] == 'bash' @@ -880,10 +877,9 @@ class TestLegacyManager(unittest.TestCase): shell='bash' )) - 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 ) # Configure the parameters that would be returned by querying the @@ -893,7 +889,7 @@ class TestLegacyManager(unittest.TestCase): {'name': 'all', 'role': 'guest'} ] current = Parameters( - dict( + params=dict( user='admin', shell='tmsh', partition_access=access @@ -901,17 +897,18 @@ class TestLegacyManager(unittest.TestCase): ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(client) - mm.is_version_less_than_13 = Mock(return_value=True) - - upm = UnparitionedManager(client) + upm = UnparitionedManager(module=module, params=module.params) upm.exists = Mock(return_value=True) upm.update_on_device = Mock(return_value=True) upm.read_current_from_device = Mock(return_value=current) + mm = ModuleManager(module=module) + mm.is_version_less_than_13 = Mock(return_value=True) + mm.get_manager = Mock(return_value=upm) + msg = "Shell access is only available to 'admin' or " \ "'resource-admin' roles" with pytest.raises(F5ModuleError) as ex: - upm.exec_module() + mm.exec_module() assert str(ex.value) == msg diff --git a/test/units/modules/network/f5/test_bigip_vcmp_guest.py b/test/units/modules/network/f5/test_bigip_vcmp_guest.py index f86828ec890..f2639eb8211 100644 --- a/test/units/modules/network/f5/test_bigip_vcmp_guest.py +++ b/test/units/modules/network/f5/test_bigip_vcmp_guest.py @@ -18,20 +18,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_vcmp_guest import Parameters from library.bigip_vcmp_guest import ModuleManager from library.bigip_vcmp_guest 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_vcmp_guest import Parameters from ansible.modules.network.f5.bigip_vcmp_guest import ModuleManager from ansible.modules.network.f5.bigip_vcmp_guest 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") @@ -70,7 +72,7 @@ class TestParameters(unittest.TestCase): ] ) - p = Parameters(args) + p = Parameters(params=args) assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso' assert p.mgmt_network == 'bridged' @@ -80,7 +82,7 @@ class TestParameters(unittest.TestCase): mgmt_address='1.2.3.4' ) - p = Parameters(args) + p = Parameters(params=args) assert p.mgmt_network == 'bridged' assert p.mgmt_address == '1.2.3.4/32' @@ -90,7 +92,7 @@ class TestParameters(unittest.TestCase): mgmt_address='1.2.3.4/24' ) - p = Parameters(args) + p = Parameters(params=args) assert p.mgmt_network == 'bridged' assert p.mgmt_address == '1.2.3.4/24' @@ -100,7 +102,7 @@ class TestParameters(unittest.TestCase): mgmt_address='1.2.3.4/255.255.255.0' ) - p = Parameters(args) + p = Parameters(params=args) assert p.mgmt_network == 'bridged' assert p.mgmt_address == '1.2.3.4/24' @@ -109,7 +111,7 @@ class TestParameters(unittest.TestCase): mgmt_route='1.2.3.4' ) - p = Parameters(args) + p = Parameters(params=args) assert p.mgmt_route == '1.2.3.4' def test_module_parameters_vcmp_software_image_facts(self): @@ -120,7 +122,7 @@ class TestParameters(unittest.TestCase): initial_image='BIGIP-12.1.0.1.0.1447-HF1.iso/1', ) - p = Parameters(args) + p = Parameters(params=args) assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso/1' def test_api_parameters(self): @@ -136,7 +138,7 @@ class TestParameters(unittest.TestCase): ] ) - p = Parameters(args) + p = Parameters(params=args) assert p.initial_image == 'BIGIP-tmos-tier2-13.1.0.0.0.931.iso' assert p.mgmt_route == '2.2.2.2' assert p.mgmt_address == '1.1.1.1/24' @@ -144,8 +146,6 @@ class TestParameters(unittest.TestCase): assert '/Common/vlan2' in p.vlans -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): self.spec = ArgumentSpec() @@ -161,14 +161,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.create_on_device = Mock(return_value=True) mm.exists = Mock(return_value=False) mm.is_deployed = Mock(side_effect=[False, True, True, True, True]) diff --git a/test/units/modules/network/f5/test_bigip_virtual_address.py b/test/units/modules/network/f5/test_bigip_virtual_address.py index 95205d0ae5b..dbb5ee389b3 100644 --- a/test/units/modules/network/f5/test_bigip_virtual_address.py +++ b/test/units/modules/network/f5/test_bigip_virtual_address.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_virtual_address import Parameters from library.bigip_virtual_address import ModuleManager from library.bigip_virtual_address 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_virtual_address import Parameters from ansible.modules.network.f5.bigip_virtual_address import ModuleManager from ansible.modules.network.f5.bigip_virtual_address 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") @@ -70,7 +72,7 @@ class TestParameters(unittest.TestCase): advertise_route='always', use_route_advertisement='yes' ) - p = Parameters(args) + p = Parameters(params=args) assert p.state == 'present' assert p.address == '1.1.1.1' assert p.netmask == '2.2.2.2' @@ -83,7 +85,7 @@ class TestParameters(unittest.TestCase): def test_api_parameters(self): args = load_fixture('load_ltm_virtual_address_default.json') - p = Parameters(args) + p = Parameters(params=args) assert p.name == '1.1.1.1' assert p.address == '1.1.1.1' assert p.arp_state == 'enabled' @@ -99,56 +101,56 @@ class TestParameters(unittest.TestCase): args = dict( advertise_route='when_all_available' ) - p = Parameters(args) + p = Parameters(params=args) assert p.advertise_route == 'all' def test_module_parameters_advertise_route_any(self): args = dict( advertise_route='when_any_available' ) - p = Parameters(args) + p = Parameters(params=args) assert p.advertise_route == 'any' def test_module_parameters_icmp_echo_disabled(self): args = dict( icmp_echo='disabled' ) - p = Parameters(args) + p = Parameters(params=args) assert p.icmp_echo == 'disabled' def test_module_parameters_icmp_echo_selective(self): args = dict( icmp_echo='selective' ) - p = Parameters(args) + p = Parameters(params=args) assert p.icmp_echo == 'selective' def test_module_parameters_auto_delete_disabled(self): args = dict( auto_delete='disabled' ) - p = Parameters(args) + p = Parameters(params=args) assert p.auto_delete is False def test_module_parameters_arp_state_disabled(self): args = dict( arp_state='disabled' ) - p = Parameters(args) + p = Parameters(params=args) assert p.arp_state == 'disabled' def test_module_parameters_use_route_advert_disabled(self): args = dict( use_route_advertisement='no' ) - p = Parameters(args) + p = Parameters(params=args) assert p.use_route_advertisement == 'disabled' def test_module_parameters_state_present(self): args = dict( state='present' ) - p = Parameters(args) + p = Parameters(params=args) assert p.state == 'present' assert p.enabled == 'yes' @@ -156,14 +158,14 @@ class TestParameters(unittest.TestCase): args = dict( state='absent' ) - p = Parameters(args) + p = Parameters(params=args) assert p.state == 'absent' def test_module_parameters_state_enabled(self): args = dict( state='enabled' ) - p = Parameters(args) + p = Parameters(params=args) assert p.state == 'enabled' assert p.enabled == 'yes' @@ -171,13 +173,11 @@ class TestParameters(unittest.TestCase): args = dict( state='disabled' ) - p = Parameters(args) + p = Parameters(params=args) assert p.state == 'disabled' assert p.enabled == 'no' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -199,12 +199,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]) @@ -222,12 +221,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=[True, False]) diff --git a/test/units/modules/network/f5/test_bigip_virtual_server.py b/test/units/modules/network/f5/test_bigip_virtual_server.py index eeb381de325..d9bb5e52c80 100644 --- a/test/units/modules/network/f5/test_bigip_virtual_server.py +++ b/test/units/modules/network/f5/test_bigip_virtual_server.py @@ -17,28 +17,24 @@ 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_virtual_server import VirtualAddressParameters - from library.bigip_virtual_server import VirtualServerModuleParameters - from library.bigip_virtual_server import VirtualServerApiParameters + from library.bigip_virtual_server import ModuleParameters + from library.bigip_virtual_server import ApiParameters from library.bigip_virtual_server import ModuleManager - from library.bigip_virtual_server import VirtualServerManager - from library.bigip_virtual_server import VirtualAddressManager from library.bigip_virtual_server 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_virtual_server import VirtualAddressParameters - from ansible.modules.network.f5.bigip_virtual_server import VirtualServerApiParameters - from ansible.modules.network.f5.bigip_virtual_server import VirtualServerModuleParameters + from ansible.modules.network.f5.bigip_virtual_server import ApiParameters + from ansible.modules.network.f5.bigip_virtual_server import ModuleParameters from ansible.modules.network.f5.bigip_virtual_server import ModuleManager - from ansible.modules.network.f5.bigip_virtual_server import VirtualServerManager - from ansible.modules.network.f5.bigip_virtual_server import VirtualAddressManager from ansible.modules.network.f5.bigip_virtual_server 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") @@ -70,14 +66,14 @@ class TestParameters(unittest.TestCase): args = dict( destination='1.1.1.1' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' def test_destination_mutex_2(self): args = dict( destination='1.1.1.1%2' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' assert p.destination_tuple.route_domain == 2 @@ -85,7 +81,7 @@ class TestParameters(unittest.TestCase): args = dict( destination='1.1.1.1:80' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' assert p.destination_tuple.port == 80 @@ -93,7 +89,7 @@ class TestParameters(unittest.TestCase): args = dict( destination='1.1.1.1%2:80' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' assert p.destination_tuple.port == 80 assert p.destination_tuple.route_domain == 2 @@ -102,14 +98,14 @@ class TestParameters(unittest.TestCase): args = dict( destination='/Common/1.1.1.1' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' def test_api_destination_mutex_6(self): args = dict( destination='/Common/1.1.1.1%2' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' assert p.destination_tuple.route_domain == 2 @@ -117,7 +113,7 @@ class TestParameters(unittest.TestCase): args = dict( destination='/Common/1.1.1.1:80' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' assert p.destination_tuple.port == 80 @@ -125,7 +121,7 @@ class TestParameters(unittest.TestCase): args = dict( destination='/Common/1.1.1.1%2:80' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '1.1.1.1' assert p.destination_tuple.port == 80 assert p.destination_tuple.route_domain == 2 @@ -134,14 +130,14 @@ class TestParameters(unittest.TestCase): args = dict( destination='2700:bc00:1f10:101::6' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '2700:bc00:1f10:101::6' def test_destination_mutex_10(self): args = dict( destination='2700:bc00:1f10:101::6%2' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '2700:bc00:1f10:101::6' assert p.destination_tuple.route_domain == 2 @@ -149,7 +145,7 @@ class TestParameters(unittest.TestCase): args = dict( destination='2700:bc00:1f10:101::6.80' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '2700:bc00:1f10:101::6' assert p.destination_tuple.port == 80 @@ -157,26 +153,11 @@ class TestParameters(unittest.TestCase): args = dict( destination='2700:bc00:1f10:101::6%2.80' ) - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.destination_tuple.ip == '2700:bc00:1f10:101::6' assert p.destination_tuple.port == 80 assert p.destination_tuple.route_domain == 2 -# -# def test_destination_mutex_6(self): -# args = dict( -# destination='/Common/2700:bc00:1f10:101::6' -# ) -# p = VirtualServerParameters(args) -# assert p.destination_tuple.ip == '2700:bc00:1f10:101::6' -# -# def test_destination_mutex_5(self): -# args = dict( -# destination='/Common/2700:bc00:1f10:101::6' -# ) -# p = VirtualServerParameters(args) -# assert p.destination_tuple.ip == '2700:bc00:1f10:101::6' - def test_module_no_partition_prefix_parameters(self): args = dict( server='localhost', @@ -198,7 +179,7 @@ class TestParameters(unittest.TestCase): ], enabled_vlans=['vlan2'] ) - p = VirtualServerModuleParameters(args) + p = ModuleParameters(params=args) assert p.name == 'my-virtual-server' assert p.partition == 'Common' assert p.port == 443 @@ -235,7 +216,7 @@ class TestParameters(unittest.TestCase): ], enabled_vlans=['/Common/vlan2'] ) - p = VirtualServerModuleParameters(args) + p = ModuleParameters(params=args) assert p.name == 'my-virtual-server' assert p.partition == 'Common' assert p.port == 443 @@ -342,7 +323,7 @@ class TestParameters(unittest.TestCase): ] } } - p = VirtualServerApiParameters(args) + p = ApiParameters(params=args) assert p.name == 'my-virtual-server' assert p.partition == 'Common' assert p.port == 443 @@ -358,8 +339,6 @@ class TestParameters(unittest.TestCase): assert '/Common/net1' in p.vlans -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -388,19 +367,15 @@ class TestManager(unittest.TestCase): validate_certs="no" )) - 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 - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=False) - vsm.create_on_device = Mock(return_value=True) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + mm = ModuleManager(module=module) + mm.exists = Mock(return_value=False) + mm.create_on_device = Mock(return_value=True) results = mm.exec_module() assert results['changed'] is True @@ -423,18 +398,14 @@ class TestManager(unittest.TestCase): validate_certs="no" )) - 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 - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=False) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + mm = ModuleManager(module=module) + mm.exists = Mock(return_value=False) results = mm.exec_module() @@ -460,26 +431,22 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = VirtualServerApiParameters( + current = ApiParameters( dict( agent_status_traps='disabled' ) ) - 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 - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=False) - vsm.update_on_device = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=current) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + mm = ModuleManager(module=module) + mm.exists = Mock(return_value=False) + mm.update_on_device = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) results = mm.exec_module() assert results['changed'] is False @@ -498,22 +465,18 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_1.json')) + current = ApiParameters(params=load_fixture('load_ltm_virtual_1.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 ) # Override methods to force specific logic in the module to happen - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=current) - vsm.update_on_device = Mock(return_value=True) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + 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) results = mm.exec_module() assert results['changed'] is True @@ -532,21 +495,17 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_1.json')) + current = ApiParameters(params=load_fixture('load_ltm_virtual_1.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 ) # Override methods to force specific logic in the module to happen - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=current) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + mm = ModuleManager(module=module) + mm.exists = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) results = mm.exec_module() assert results['changed'] is False @@ -567,21 +526,17 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_2.json')) + current = ApiParameters(params=load_fixture('load_ltm_virtual_2.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 ) # Override methods to force specific logic in the module to happen - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=current) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + mm = ModuleManager(module=module) + mm.exists = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) results = mm.exec_module() @@ -603,22 +558,18 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_2.json')) + current = ApiParameters(params=load_fixture('load_ltm_virtual_2.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 ) # Override methods to force specific logic in the module to happen - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=current) - vsm.update_on_device = Mock(return_value=True) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + 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) results = mm.exec_module() @@ -674,22 +625,18 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_3.json')) + current = ApiParameters(params=load_fixture('load_ltm_virtual_3.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 ) # Override methods to force specific logic in the module to happen - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=current) - vsm.update_on_device = Mock(return_value=True) - - mm = ModuleManager(client) - mm.get_manager = Mock(return_value=vsm) + 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) results = mm.exec_module() @@ -727,47 +674,3 @@ class TestManager(unittest.TestCase): assert 'context' in results['profiles'][1] assert results['profiles'][1]['name'] == 'clientssl' assert results['profiles'][1]['context'] == 'clientside' - - -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) -class TestDeprecatedAnsible24Manager(unittest.TestCase): - def setUp(self): - self.spec = ArgumentSpec() - - def test_modify_port_idempotent(self, *args): - set_module_args(dict( - destination="10.10.10.10", - name="my-virtual-server", - route_advertisement_state="enabled", - partition="Common", - password="secret", - port="443", - server="localhost", - state="present", - user="admin", - validate_certs="no" - )) - - client = AnsibleF5Client( - argument_spec=self.spec.argument_spec, - supports_check_mode=self.spec.supports_check_mode, - f5_product_name=self.spec.f5_product_name - ) - - vsm_current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_1.json')) - vam_current = VirtualAddressParameters(load_fixture('load_ltm_virtual_1_address.json')) - - vsm = VirtualServerManager(client) - vsm.exists = Mock(return_value=True) - vsm.read_current_from_device = Mock(return_value=vsm_current) - vam = VirtualAddressManager(client) - vam.exists = Mock(return_value=True) - vam.read_current_from_device = Mock(return_value=vam_current) - - mm = ModuleManager(client) - mm.get_manager = Mock(side_effect=[vsm, vam]) - - results = mm.exec_module() - - assert results['changed'] is False diff --git a/test/units/modules/network/f5/test_bigip_vlan.py b/test/units/modules/network/f5/test_bigip_vlan.py index 74dffbfda9b..322e233b690 100644 --- a/test/units/modules/network/f5/test_bigip_vlan.py +++ b/test/units/modules/network/f5/test_bigip_vlan.py @@ -8,7 +8,6 @@ __metaclass__ = type import os import json -import pytest import sys from nose.plugins.skip import SkipTest @@ -18,21 +17,24 @@ 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_vlan import Parameters + from library.bigip_vlan import ApiParameters + from library.bigip_vlan import ModuleParameters from library.bigip_vlan import ModuleManager from library.bigip_vlan 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_vlan import Parameters + from ansible.modules.network.f5.bigip_vlan import ApiParameters + from ansible.modules.network.f5.bigip_vlan import ModuleParameters from ansible.modules.network.f5.bigip_vlan import ModuleManager from ansible.modules.network.f5.bigip_vlan 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,13 +67,6 @@ class BigIpObj(object): class TestParameters(unittest.TestCase): - - def setUp(self): - self.loaded_ifcs = [] - ifcs_json = load_fixture('load_net_interfaces.json') - for item in ifcs_json: - self.loaded_ifcs.append(BigIpObj(**item)) - def test_module_parameters(self): args = dict( name='somevlan', @@ -79,9 +74,7 @@ class TestParameters(unittest.TestCase): description='fakevlan', untagged_interfaces=['1.1'], ) - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - p = Parameters(args) + p = ModuleParameters(params=args) assert p.name == 'somevlan' assert p.tag == 213 @@ -92,38 +85,20 @@ class TestParameters(unittest.TestCase): args = dict( name='somevlan', description='fakevlan', - tag=213, - tagged_interfaces=['1.2'] + tag=213 ) - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - p = Parameters(args) + p = ApiParameters(params=args) assert p.name == 'somevlan' assert p.tag == 213 - assert p.interfaces == [{'tagged': True, 'name': '1.2'}] assert p.description == 'fakevlan' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): self.spec = ArgumentSpec() - self.loaded_ifcs = [] - self.loaded_vlan_ifc_tag = [] - self.loaded_vlan_ifc_untag = [] - ifcs_tag = load_fixture('load_vlan_tagged_ifcs.json') - ifcs_untag = load_fixture('load_vlan_untag_ifcs.json') - ifcs_json = load_fixture('load_net_interfaces.json') - for item in ifcs_json: - self.loaded_ifcs.append(BigIpObj(**item)) - for item in ifcs_tag: - self.loaded_vlan_ifc_tag.append(BigIpObj(**item)) - for item in ifcs_untag: - self.loaded_vlan_ifc_untag.append(BigIpObj(**item)) def test_create_vlan(self, *args): set_module_args(dict( @@ -135,24 +110,19 @@ class TestManager(unittest.TestCase): partition='Common' )) - 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 - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs + mm = ModuleManager(module=module) + mm.create_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=False) - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) - - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['name'] == 'somevlan' assert results['description'] == 'fakevlan' def test_create_vlan_tagged_interface(self, *args): @@ -166,26 +136,21 @@ class TestManager(unittest.TestCase): partition='Common' )) - 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 - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.create_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=False) - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['interfaces'] == [{'tagged': True, 'name': '2.1'}] + assert results['tagged_interfaces'] == ['2.1'] assert results['tag'] == 213 - assert results['name'] == 'somevlan' def test_create_vlan_untagged_interface(self, *args): set_module_args(dict( @@ -197,25 +162,20 @@ class TestManager(unittest.TestCase): partition='Common' )) - 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 - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs + mm = ModuleManager(module=module) + mm.create_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=False) - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) - - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['interfaces'] == [{'untagged': True, 'name': '2.1'}] - assert results['name'] == 'somevlan' + assert results['untagged_interfaces'] == ['2.1'] def test_create_vlan_tagged_interfaces(self, *args): set_module_args(dict( @@ -228,27 +188,21 @@ class TestManager(unittest.TestCase): partition='Common' )) - 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 - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) + mm = ModuleManager(module=module) + mm.create_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=False) - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['interfaces'] == [{'tagged': True, 'name': '2.1'}, - {'tagged': True, 'name': '1.1'}] + assert results['tagged_interfaces'] == ['1.1', '2.1'] assert results['tag'] == 213 - assert results['name'] == 'somevlan' def test_create_vlan_untagged_interfaces(self, *args): set_module_args(dict( @@ -260,26 +214,20 @@ class TestManager(unittest.TestCase): partition='Common', )) - 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 - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs + mm = ModuleManager(module=module) + mm.create_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=False) - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) - - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['interfaces'] == [{'untagged': True, 'name': '2.1'}, - {'untagged': True, 'name': '1.1'}] - assert results['name'] == 'somevlan' + assert results['untagged_interfaces'] == ['1.1', '2.1'] def test_update_vlan_untag_interface(self, *args): set_module_args(dict( @@ -291,32 +239,26 @@ class TestManager(unittest.TestCase): partition='Common', )) - 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 ) - ifcs = self.loaded_vlan_ifc_untag + # Override methods to force specific logic in the module to happen - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - mm = ModuleManager(client) + mm = ModuleManager(module=module) - current = ( - Parameters( - load_fixture('load_vlan.json') - ), - ifcs - ) + current = ApiParameters(params=load_fixture('load_vlan.json')) + interfaces = load_fixture('load_vlan_interfaces.json') + current.update({'interfaces': interfaces}) - mm.update_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=True) - mm.read_current_from_device = Mock(return_value=current) + mm.update_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['interfaces'] == [{'untagged': True, 'name': '2.1'}] + assert results['untagged_interfaces'] == ['2.1'] def test_update_vlan_tag_interface(self, *args): set_module_args(dict( @@ -328,32 +270,24 @@ class TestManager(unittest.TestCase): partition='Common', )) - 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 ) - ifcs = self.loaded_vlan_ifc_tag + # Override methods to force specific logic in the module to happen - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - mm = ModuleManager(client) + mm = ModuleManager(module=module) - current = ( - Parameters( - load_fixture('load_vlan.json') - ), - ifcs - ) + current = ApiParameters(params=load_fixture('load_vlan.json')) - mm.update_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=True) - mm.read_current_from_device = Mock(return_value=current) + mm.update_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True - assert results['interfaces'] == [{'tagged': True, 'name': '2.1'}] + assert results['tagged_interfaces'] == ['2.1'] def test_update_vlan_description(self, *args): set_module_args(dict( @@ -365,117 +299,21 @@ class TestManager(unittest.TestCase): partition='Common', )) - 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 ) - ifcs = self.loaded_vlan_ifc_tag + # Override methods to force specific logic in the module to happen - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - mm = ModuleManager(client) + mm = ModuleManager(module=module) - current = ( - Parameters( - load_fixture('update_vlan_description.json') - ), - ifcs - ) + current = ApiParameters(params=load_fixture('update_vlan_description.json')) - mm.update_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=True) - mm.read_current_from_device = Mock(return_value=current) + mm.update_on_device = Mock(return_value=True) + mm.exists = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) - results = mm.exec_module() + results = mm.exec_module() assert results['changed'] is True assert results['description'] == 'changed_that' - - def test_untagged_ifc_raises(self, *args): - set_module_args(dict( - name='somevlan', - untagged_interface=['10.2'], - server='localhost', - password='password', - user='admin', - partition='Common' - )) - - client = AnsibleF5Client( - argument_spec=self.spec.argument_spec, - supports_check_mode=self.spec.supports_check_mode, - f5_product_name=self.spec.f5_product_name - ) - msg = 'The specified interface "10.2" was not found' - # Override methods to force specific logic in the module to happen - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) - - with pytest.raises(F5ModuleError) as err: - mm.exec_module() - - assert str(err.value) == msg - - def test_tagged_ifc_raises(self, *args): - set_module_args(dict( - name='somevlan', - tagged_interface=['10.2'], - tag=213, - server='localhost', - password='password', - user='admin', - partition='Common' - )) - - client = AnsibleF5Client( - argument_spec=self.spec.argument_spec, - supports_check_mode=self.spec.supports_check_mode, - f5_product_name=self.spec.f5_product_name - ) - msg = 'The specified interface "10.2" was not found' - # Override methods to force specific logic in the module to happen - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = self.loaded_ifcs - - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) - - with pytest.raises(F5ModuleError) as err: - mm.exec_module() - - assert str(err.value) == msg - - def test_parse_return_ifcs_raises(self, *args): - set_module_args(dict( - name='somevlan', - untagged_interface=['1.2'], - server='localhost', - password='password', - user='admin', - partition='Common' - )) - - client = AnsibleF5Client( - argument_spec=self.spec.argument_spec, - supports_check_mode=self.spec.supports_check_mode, - f5_product_name=self.spec.f5_product_name - ) - msg = 'No interfaces were found' - # Override methods to force specific logic in the module to happen - with patch.object(Parameters, '_get_interfaces_from_device') as obj: - obj.return_value = [] - - mm = ModuleManager(client) - mm.create_on_device = Mock(return_value=True) - mm.exists = Mock(return_value=False) - - with pytest.raises(F5ModuleError) as err: - mm.exec_module() - - assert str(err.value) == msg diff --git a/test/units/modules/network/f5/test_bigip_wait.py b/test/units/modules/network/f5/test_bigip_wait.py index f32303f4984..964d1ec7911 100644 --- a/test/units/modules/network/f5/test_bigip_wait.py +++ b/test/units/modules/network/f5/test_bigip_wait.py @@ -18,23 +18,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.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule try: from library.bigip_wait import Parameters from library.bigip_wait import ModuleManager from library.bigip_wait import ArgumentSpec - from library.bigip_wait import AnsibleF5ClientStub - 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_wait import Parameters from ansible.modules.network.f5.bigip_wait import ModuleManager from ansible.modules.network.f5.bigip_wait import ArgumentSpec - from ansible.modules.network.f5.bigip_wait import AnsibleF5ClientStub - 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") @@ -70,7 +69,7 @@ class TestParameters(unittest.TestCase): msg='We timed out during waiting for BIG-IP :-(' ) - p = Parameters(args) + p = Parameters(params=args) assert p.delay == 3 assert p.timeout == 500 assert p.sleep == 10 @@ -84,15 +83,13 @@ class TestParameters(unittest.TestCase): msg='We timed out during waiting for BIG-IP :-(' ) - p = Parameters(args) + p = Parameters(params=args) assert p.delay == 3 assert p.timeout == 500 assert p.sleep == 10 assert p.msg == 'We timed out during waiting for BIG-IP :-(' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): self.spec = ArgumentSpec() @@ -104,14 +101,13 @@ class TestManager(unittest.TestCase): user='admin' )) - client = AnsibleF5ClientStub( + 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._connect_to_device = Mock(return_value=True) mm._device_is_rebooting = Mock(return_value=False) mm._is_mprov_running_on_device = Mock(return_value=False) diff --git a/test/units/modules/network/f5/test_bigiq_regkey_license.py b/test/units/modules/network/f5/test_bigiq_regkey_license.py index c0c94cfa4a1..cf193ab8b07 100644 --- a/test/units/modules/network/f5/test_bigiq_regkey_license.py +++ b/test/units/modules/network/f5/test_bigiq_regkey_license.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.bigiq_regkey_license import ModuleParameters from library.bigiq_regkey_license import ApiParameters from library.bigiq_regkey_license import ModuleManager from library.bigiq_regkey_license 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.bigiq_regkey_license import ApiParameters from ansible.modules.network.f5.bigiq_regkey_license import ModuleManager from ansible.modules.network.f5.bigiq_regkey_license 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") @@ -70,7 +71,7 @@ class TestParameters(unittest.TestCase): description='this is a description' ) - p = ModuleParameters(args) + p = ModuleParameters(params=args) assert p.regkey_pool == 'foo' assert p.license_key == 'XXXX-XXXX-XXXX-XXXX-XXXX' assert p.accept_eula is True @@ -79,12 +80,10 @@ class TestParameters(unittest.TestCase): def test_api_parameters(self): args = load_fixture('load_regkey_license_key.json') - p = ApiParameters(args) + p = ApiParameters(params=args) assert p.description == 'foo bar baz' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -101,12 +100,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]) diff --git a/test/units/modules/network/f5/test_bigiq_regkey_pool.py b/test/units/modules/network/f5/test_bigiq_regkey_pool.py index 53c9eb581bb..555b4e2601b 100644 --- a/test/units/modules/network/f5/test_bigiq_regkey_pool.py +++ b/test/units/modules/network/f5/test_bigiq_regkey_pool.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.f5_utils import F5ModuleError +from ansible.module_utils.basic import AnsibleModule try: from library.bigiq_regkey_pool import ModuleParameters from library.bigiq_regkey_pool import ApiParameters from library.bigiq_regkey_pool import ModuleManager from library.bigiq_regkey_pool import ArgumentSpec + 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,6 +34,8 @@ except ImportError: from ansible.modules.network.f5.bigiq_regkey_pool import ApiParameters from ansible.modules.network.f5.bigiq_regkey_pool import ModuleManager from ansible.modules.network.f5.bigiq_regkey_pool import ArgumentSpec + 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,18 +68,16 @@ class TestParameters(unittest.TestCase): description='this is a description' ) - p = ModuleParameters(args) + p = ModuleParameters(params=args) assert p.description == 'this is a description' def test_api_parameters(self): args = load_fixture('load_regkey_license_pool.json') - p = ApiParameters(args) + p = ApiParameters(params=args) assert p.description == 'this is a description' -@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', - return_value=True) class TestManager(unittest.TestCase): def setUp(self): @@ -91,14 +92,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(return_value=False) mm.create_on_device = Mock(return_value=True)