diff --git a/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py b/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py
index 216a62c0ef..beb7b2b54b 100644
--- a/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py
+++ b/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
-# (c) 2015, Michael Perzel
+# Copyright 2017 F5 Networks Inc.
#
# This file is part of Ansible
#
@@ -18,150 +18,540 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see .
-ANSIBLE_METADATA = {'metadata_version': '1.0',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
+ANSIBLE_METADATA = {
+ 'status': ['preview'],
+ 'supported_by': 'community',
+ 'metadata_version': '1.0'
+}
DOCUMENTATION = '''
---
module: bigip_gtm_wide_ip
-short_description: "Manages F5 BIG-IP GTM wide ip"
+short_description: Manages F5 BIG-IP GTM wide ip.
description:
- - "Manages F5 BIG-IP GTM wide ip"
+ - Manages F5 BIG-IP GTM wide ip.
version_added: "2.0"
-author:
- - Michael Perzel (@perzizzle)
- - Tim Rupp (@caphrim007)
-notes:
- - "Requires BIG-IP software version >= 11.4"
- - "F5 developed module 'bigsuds' required (see http://devcentral.f5.com)"
- - "Best run as a local_action in your playbook"
- - "Tested with manager and above account privilege level"
-
-requirements:
- - bigsuds
options:
- lb_method:
- description:
- - LB method of wide ip
- required: true
- choices: ['return_to_dns', 'null', 'round_robin',
- 'ratio', 'topology', 'static_persist', 'global_availability',
- 'vs_capacity', 'least_conn', 'lowest_rtt', 'lowest_hops',
- 'packet_rate', 'cpu', 'hit_ratio', 'qos', 'bps',
- 'drop_packet', 'explicit_ip', 'connection_rate', 'vs_score']
- wide_ip:
- description:
- - Wide IP name
- required: true
+ lb_method:
+ description:
+ - Specifies the load balancing method used to select a pool in this wide
+ IP. This setting is relevant only when multiple pools are configured
+ for a wide IP.
+ required: True
+ choices:
+ - round-robin
+ - ratio
+ - topology
+ - global-availability
+ name:
+ description:
+ - Wide IP name. This name must be formatted as a fully qualified
+ domain name (FQDN). You can also use the alias C(wide_ip) but this
+ is deprecated and will be removed in a future Ansible version.
+ required: True
+ aliases:
+ - wide_ip
+ type:
+ description:
+ - Specifies the type of wide IP. GTM wide IPs need to be keyed by query
+ type in addition to name, since pool members need different attributes
+ depending on the response RDATA they are meant to supply. This value
+ is required if you are using BIG-IP versions >= 12.0.0.
+ choices:
+ - a
+ - aaaa
+ - cname
+ - mx
+ - naptr
+ - srv
+ version_added: 2.4
+ state:
+ description:
+ - When C(present) or C(enabled), ensures that the Wide IP exists and
+ is enabled. When C(absent), ensures that the Wide IP has been
+ removed. When C(disabled), ensures that the Wide IP exists and is
+ disabled.
+ default: present
+ choices:
+ - present
+ - absent
+ - disabled
+ - enabled
+ version_added: 2.4
+notes:
+ - Requires the f5-sdk Python package on the host. This is as easy as pip
+ install f5-sdk.
extends_documentation_fragment: f5
+requirements:
+ - f5-sdk
+author:
+ - Tim Rupp (@caphrim007)
'''
EXAMPLES = '''
- - name: Set lb method
- local_action: >
- bigip_gtm_wide_ip
- server=192.0.2.1
- user=admin
- password=mysecret
- lb_method=round_robin
- wide_ip=my-wide-ip.example.com
+- name: Set lb method
+ bigip_gtm_wide_ip:
+ server: "lb.mydomain.com"
+ user: "admin"
+ password: "secret"
+ lb_method: "round-robin"
+ name: "my-wide-ip.example.com"
+ delegate_to: localhost
'''
-try:
- import bigsuds
-except ImportError:
- bigsuds_found = False
-else:
- bigsuds_found = True
+RETURN = '''
+lb_method:
+ description: The new load balancing method used by the wide IP.
+ returned: changed
+ type: string
+ sample: "topology"
+state:
+ description: The new state of the wide IP.
+ returned: changed
+ type: string
+ sample: "disabled"
+'''
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.pycompat24 import get_exception
-from ansible.module_utils.f5_utils import bigip_api, f5_argument_spec
+import re
+
+from ansible.module_utils.f5_utils import (
+ AnsibleF5Client,
+ AnsibleF5Parameters,
+ HAS_F5SDK,
+ F5ModuleError,
+ iControlUnexpectedHTTPError
+)
+from distutils.version import LooseVersion
-def get_wide_ip_lb_method(api, wide_ip):
- lb_method = api.GlobalLB.WideIP.get_lb_method(wide_ips=[wide_ip])[0]
- lb_method = lb_method.strip().replace('LB_METHOD_', '').lower()
- return lb_method
+class Parameters(AnsibleF5Parameters):
+ updatables = ['lb_method']
+ returnables = ['name', 'lb_method', 'state']
+ api_attributes = ['poolLbMode', 'enabled', 'disabled']
-def get_wide_ip_pools(api, wide_ip):
- try:
- return api.GlobalLB.WideIP.get_wideip_pool([wide_ip])
- except Exception:
- e = get_exception()
- print(e)
+ def to_return(self):
+ result = {}
+ for returnable in self.returnables:
+ result[returnable] = getattr(self, returnable)
+ result = self._filter_params(result)
+ return result
-def wide_ip_exists(api, wide_ip):
- # hack to determine if wide_ip exists
- result = False
- try:
- api.GlobalLB.WideIP.get_object_status(wide_ips=[wide_ip])
- result = True
- except bigsuds.OperationFailed:
- e = get_exception()
- if "was not found" in str(e):
- result = False
+ 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 lb_method(self):
+ deprecated = [
+ 'return_to_dns', 'null', 'static_persist', 'vs_capacity',
+ 'least_conn', 'lowest_rtt', 'lowest_hops', 'packet_rate', 'cpu',
+ 'hit_ratio', 'qos', 'bps', 'drop_packet', 'explicit_ip',
+ 'connection_rate', 'vs_score'
+ ]
+ if self._values['lb_method'] is None:
+ return None
+ lb_method = str(self._values['lb_method'])
+ if lb_method in deprecated:
+ raise F5ModuleError(
+ "The provided lb_method is not supported"
+ )
+ elif lb_method == 'global_availability':
+ if self._values['__warnings'] is None:
+ self._values['__warnings'] = []
+ self._values['__warnings'].append(
+ dict(
+ msg='The provided lb_method is deprecated',
+ version='2.4'
+ )
+ )
+ lb_method = 'global-availability'
+ elif lb_method == 'round_robin':
+ if self._values['__warnings'] is None:
+ self._values['__warnings'] = []
+ self._values['__warnings'].append(
+ dict(
+ msg='The provided lb_method is deprecated',
+ version='2.4'
+ )
+ )
+ lb_method = 'round-robin'
+ return lb_method
+
+ @lb_method.setter
+ def lb_method(self, value):
+ self._values['lb_method'] = value
+
+ @property
+ def collection(self):
+ type_map = dict(
+ a='a_s',
+ aaaa='aaaas',
+ cname='cnames',
+ mx='mxs',
+ naptr='naptrs',
+ srv='srvs'
+ )
+ if self._values['type'] is None:
+ return None
+ wideip_type = self._values['type']
+ return type_map[wideip_type]
+
+ @property
+ def type(self):
+ if self._values['type'] is None:
+ return None
+ return str(self._values['type'])
+
+ @property
+ def name(self):
+ if self._values['name'] is None:
+ return None
+ if not re.search(r'.*\..*\..*', self._values['name']):
+ raise F5ModuleError(
+ "The provided name must be a valid FQDN"
+ )
+ return self._values['name']
+
+ @property
+ def poolLbMode(self):
+ return self.lb_method
+
+ @poolLbMode.setter
+ def poolLbMode(self, value):
+ self.lb_method = value
+
+ @property
+ def state(self):
+ if self._values['state'] == 'enabled':
+ return 'present'
+ return self._values['state']
+
+ @property
+ def enabled(self):
+ if self._values['state'] == 'disabled':
+ return False
+ elif self._values['state'] in ['present', 'enabled']:
+ return True
+ elif self._values['enabled'] is True:
+ return True
else:
- # genuine exception
- raise
- return result
+ return None
+
+ @property
+ def disabled(self):
+ if self._values['state'] == 'disabled':
+ return True
+ elif self._values['state'] in ['present', 'enabled']:
+ return False
+ elif self._values['disabled'] is True:
+ return True
+ else:
+ return None
+
+
+class ModuleManager(object):
+ def __init__(self, client):
+ self.client = client
+
+ def exec_module(self):
+ if self.version_is_less_than_12():
+ manager = self.get_manager('untyped')
+ else:
+ manager = self.get_manager('typed')
+ return manager.exec_module()
+
+ def get_manager(self, type):
+ if type == 'typed':
+ return TypedManager(self.client)
+ elif type == 'untyped':
+ return UntypedManager(self.client)
+
+ def version_is_less_than_12(self):
+ version = self.client.api.tmos_version
+ if LooseVersion(version) < LooseVersion('12.0.0'):
+ return True
+ else:
+ return False
+
+
+class BaseManager(object):
+ def __init__(self, client):
+ self.client = client
+ self.have = None
+ self.want = Parameters(self.client.module.params)
+ self.changes = Parameters()
+
+ 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 self.want.state == 'disabled' and self.have.enabled:
+ changed['state'] = self.want.state
+ elif self.want.state in ['present', 'enabled'] and self.have.disabled:
+ changed['state'] = self.want.state
+
+ if changed:
+ self.changes = Parameters(changed)
+ return True
+ return False
+
+ def exec_module(self):
+ changed = False
+ result = dict()
+ state = self.want.state
+
+ try:
+ if state in ["present", "disabled"]:
+ changed = self.present()
+ elif state == "absent":
+ changed = self.absent()
+ except iControlUnexpectedHTTPError as e:
+ raise F5ModuleError(str(e))
+
+ changes = self.changes.to_return()
+ result.update(**changes)
+ result.update(dict(changed=changed))
+ self._announce_deprecations()
+ return result
+
+ def _announce_deprecations(self):
+ warnings = []
+ if self.want:
+ warnings += self.want._values.get('__warnings', [])
+ if self.have:
+ warnings += self.have._values.get('__warnings', [])
+ for warning in warnings:
+ self.client.module.deprecate(
+ msg=warning['msg'],
+ version=warning['version']
+ )
+
+ def present(self):
+ if self.want.lb_method is None:
+ raise F5ModuleError(
+ "The 'lb_method' option is required when state is 'present'"
+ )
+ if self.exists():
+ return self.update()
+ else:
+ return self.create()
+
+ def create(self):
+ self._set_changed_options()
+ if self.client.check_mode:
+ return True
+ self.create_on_device()
+ return True
+
+ def should_update(self):
+ result = self._update_changed_options()
+ if result:
+ return True
+ return False
+
+ def update(self):
+ self.have = self.read_current_from_device()
+ if not self.should_update():
+ return False
+ if self.client.check_mode:
+ return True
+ self.update_on_device()
+ return True
+
+ def absent(self):
+ if self.exists():
+ return self.remove()
+ return False
+
+ def remove(self):
+ if self.client.check_mode:
+ return True
+ self.remove_from_device()
+ if self.exists():
+ raise F5ModuleError("Failed to delete the Wide IP")
+ return True
+
+
+class UntypedManager(BaseManager):
+ def exists(self):
+ return self.client.api.tm.gtm.wideips.wideip.exists(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+
+ def update_on_device(self):
+ params = self.want.api_params()
+ result = self.client.api.tm.gtm.wideips.wipeip.load(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ result.modify(**params)
+
+ def read_current_from_device(self):
+ resource = self.client.api.tm.gtm.wideips.wideip.load(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ result = resource.attrs
+ return Parameters(result)
+
+ def create_on_device(self):
+ params = self.want.api_params()
+ self.client.api.tm.gtm.wideips.wideip.create(
+ name=self.want.name,
+ partition=self.want.partition,
+ **params
+ )
+
+ def remove_from_device(self):
+ result = self.client.api.tm.gtm.wideips.wideip.load(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ if result:
+ result.delete()
+
+
+class TypedManager(BaseManager):
+ def __init__(self, client):
+ super(TypedManager, self).__init__(client)
+ if self.want.type is None:
+ raise F5ModuleError(
+ "The 'type' option is required for BIG-IP instances "
+ "greater than or equal to 12.x"
+ )
+
+ def exists(self):
+ wideips = self.client.api.tm.gtm.wideips
+ collection = getattr(wideips, self.want.collection)
+ resource = getattr(collection, self.want.type)
+ result = resource.exists(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ return result
+
+ def update_on_device(self):
+ params = self.want.api_params()
+ wideips = self.client.api.tm.gtm.wideips
+ collection = getattr(wideips, self.want.collection)
+ resource = getattr(collection, self.want.type)
+ result = resource.load(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ result.modify(**params)
+
+ def read_current_from_device(self):
+ wideips = self.client.api.tm.gtm.wideips
+ collection = getattr(wideips, self.want.collection)
+ resource = getattr(collection, self.want.type)
+ result = resource.load(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ result = result.attrs
+ return Parameters(result)
+
+ def create_on_device(self):
+ params = self.want.api_params()
+ wideips = self.client.api.tm.gtm.wideips
+ collection = getattr(wideips, self.want.collection)
+ resource = getattr(collection, self.want.type)
+ resource.create(
+ name=self.want.name,
+ partition=self.want.partition,
+ **params
+ )
+
+ def remove_from_device(self):
+ wideips = self.client.api.tm.gtm.wideips
+ collection = getattr(wideips, self.want.collection)
+ resource = getattr(collection, self.want.type)
+ result = resource.load(
+ name=self.want.name,
+ partition=self.want.partition
+ )
+ if result:
+ result.delete()
+
+
+class ArgumentSpec(object):
+ def __init__(self):
+ deprecated = [
+ 'return_to_dns', 'null', 'round_robin', 'static_persist',
+ 'global_availability', 'vs_capacity', 'least_conn', 'lowest_rtt',
+ 'lowest_hops', 'packet_rate', 'cpu', 'hit_ratio', 'qos', 'bps',
+ 'drop_packet', 'explicit_ip', 'connection_rate', 'vs_score'
+ ]
+ supported = [
+ 'round-robin', 'topology', 'ratio', 'global-availability'
+ ]
+ lb_method_choices = deprecated + supported
+ self.supports_check_mode = True
+ self.argument_spec = dict(
+ lb_method=dict(
+ required=False,
+ choices=lb_method_choices,
+ default=None
+ ),
+ name=dict(
+ required=True,
+ aliases=['wide_ip']
+ ),
+ type=dict(
+ required=False,
+ default=None,
+ choices=[
+ 'a', 'aaaa', 'cname', 'mx', 'naptr', 'srv'
+ ]
+ ),
+ state=dict(
+ required=False,
+ default='present',
+ choices=['absent', 'present', 'enabled', 'disabled']
+ )
+ )
+ self.f5_product_name = 'bigip'
-def set_wide_ip_lb_method(api, wide_ip, lb_method):
- lb_method = "LB_METHOD_%s" % lb_method.strip().upper()
- api.GlobalLB.WideIP.set_lb_method(wide_ips=[wide_ip], lb_methods=[lb_method])
def main():
- argument_spec = f5_argument_spec()
+ if not HAS_F5SDK:
+ raise F5ModuleError("The python f5-sdk module is required")
- lb_method_choices = ['return_to_dns', 'null', 'round_robin',
- 'ratio', 'topology', 'static_persist', 'global_availability',
- 'vs_capacity', 'least_conn', 'lowest_rtt', 'lowest_hops',
- 'packet_rate', 'cpu', 'hit_ratio', 'qos', 'bps',
- 'drop_packet', 'explicit_ip', 'connection_rate', 'vs_score']
- meta_args = dict(
- lb_method = dict(type='str', required=True, choices=lb_method_choices),
- wide_ip = dict(type='str', required=True)
+ spec = ArgumentSpec()
+
+ client = AnsibleF5Client(
+ argument_spec=spec.argument_spec,
+ supports_check_mode=spec.supports_check_mode,
+ f5_product_name=spec.f5_product_name
)
- argument_spec.update(meta_args)
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- if not bigsuds_found:
- module.fail_json(msg="the python bigsuds module is required")
-
- server = module.params['server']
- server_port = module.params['server_port']
- user = module.params['user']
- password = module.params['password']
- wide_ip = module.params['wide_ip']
- lb_method = module.params['lb_method']
- validate_certs = module.params['validate_certs']
-
- result = {'changed': False} # default
try:
- api = bigip_api(server, user, password, validate_certs, port=server_port)
-
- if not wide_ip_exists(api, wide_ip):
- module.fail_json(msg="wide ip %s does not exist" % wide_ip)
-
- if lb_method is not None and lb_method != get_wide_ip_lb_method(api, wide_ip):
- if not module.check_mode:
- set_wide_ip_lb_method(api, wide_ip, lb_method)
- result = {'changed': True}
- else:
- result = {'changed': True}
-
- except Exception:
- e = get_exception()
- module.fail_json(msg="received exception: %s" % e)
-
- module.exit_json(**result)
+ mm = ModuleManager(client)
+ results = mm.exec_module()
+ client.module.exit_json(**results)
+ except F5ModuleError as e:
+ client.module.fail_json(msg=str(e))
if __name__ == '__main__':
diff --git a/test/sanity/pep8/legacy-files.txt b/test/sanity/pep8/legacy-files.txt
index 8464453eec..ce83d1af9d 100644
--- a/test/sanity/pep8/legacy-files.txt
+++ b/test/sanity/pep8/legacy-files.txt
@@ -325,7 +325,6 @@ lib/ansible/modules/network/eos/eos_facts.py
lib/ansible/modules/network/eos/eos_system.py
lib/ansible/modules/network/eos/eos_user.py
lib/ansible/modules/network/f5/bigip_gtm_facts.py
-lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py
lib/ansible/modules/network/f5/bigip_virtual_server.py
lib/ansible/modules/network/fortios/fortios_config.py
lib/ansible/modules/network/fortios/fortios_ipv4_policy.py
diff --git a/test/units/modules/network/f5/test_bigip_gtm_wide_ip.py b/test/units/modules/network/f5/test_bigip_gtm_wide_ip.py
new file mode 100644
index 0000000000..0512edda0f
--- /dev/null
+++ b/test/units/modules/network/f5/test_bigip_gtm_wide_ip.py
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2017 F5 Networks Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import sys
+
+if sys.version_info < (2, 7):
+ from nose.plugins.skip import SkipTest
+ raise SkipTest("F5 Ansible modules require Python >= 2.7")
+
+import os
+import json
+import pytest
+
+from ansible.compat.tests import unittest
+from ansible.compat.tests.mock import patch, Mock
+from ansible.module_utils import basic
+from ansible.module_utils._text import to_bytes
+from ansible.module_utils.f5_utils import AnsibleF5Client
+from ansible.module_utils.f5_utils import F5ModuleError
+
+try:
+ from library.bigip_gtm_wide_ip import Parameters
+ from library.bigip_gtm_wide_ip import ModuleManager
+ from library.bigip_gtm_wide_ip import ArgumentSpec
+ from library.bigip_gtm_wide_ip import UntypedManager
+ from library.bigip_gtm_wide_ip import TypedManager
+except ImportError:
+ from ansible.modules.network.f5.bigip_gtm_wide_ip import Parameters
+ from ansible.modules.network.f5.bigip_gtm_wide_ip import ModuleManager
+ from ansible.modules.network.f5.bigip_gtm_wide_ip import ArgumentSpec
+ from ansible.modules.network.f5.bigip_gtm_wide_ip import UntypedManager
+ from ansible.modules.network.f5.bigip_gtm_wide_ip import TypedManager
+
+fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
+fixture_data = {}
+
+
+def set_module_args(args):
+ args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ basic._ANSIBLE_ARGS = to_bytes(args)
+
+
+def load_fixture(name):
+ path = os.path.join(fixture_path, name)
+
+ if path in fixture_data:
+ return fixture_data[path]
+
+ with open(path) as f:
+ data = f.read()
+
+ try:
+ data = json.loads(data)
+ except Exception:
+ pass
+
+ fixture_data[path] = data
+ return data
+
+
+class TestParameters(unittest.TestCase):
+ def test_module_parameters(self):
+ args = dict(
+ name='foo.baz.bar',
+ lb_method='round-robin'
+ )
+ p = Parameters(args)
+ assert p.name == 'foo.baz.bar'
+ assert p.lb_method == 'round-robin'
+
+ def test_api_parameters(self):
+ args = dict(
+ name='foo.baz.bar',
+ poolLbMode='round-robin'
+ )
+ p = Parameters(args)
+ assert p.name == 'foo.baz.bar'
+ assert p.lb_method == 'round-robin'
+
+ def test_api_not_fqdn_name(self):
+ args = dict(
+ name='foo.baz',
+ poolLbMode='round-robin'
+ )
+ with pytest.raises(F5ModuleError) as excinfo:
+ p = Parameters(args)
+ assert p.name == 'foo.baz'
+ assert 'The provided name must be a valid FQDN' in str(excinfo)
+
+
+@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
+ return_value=True)
+class TestUntypedManager(unittest.TestCase):
+
+ def setUp(self):
+ self.spec = ArgumentSpec()
+
+ def test_create_wideip(self, *args):
+ set_module_args(dict(
+ name='foo.baz.bar',
+ lb_method='round-robin',
+ password='passsword',
+ server='localhost',
+ user='admin'
+ ))
+
+ client = AnsibleF5Client(
+ argument_spec=self.spec.argument_spec,
+ supports_check_mode=self.spec.supports_check_mode,
+ f5_product_name=self.spec.f5_product_name
+ )
+
+ # Override methods in the specific type of manager
+ tm = UntypedManager(client)
+ tm.exists = Mock(return_value=False)
+ tm.create_on_device = Mock(return_value=True)
+
+ # Override methods to force specific logic in the module to happen
+ mm = ModuleManager(client)
+ mm.version_is_less_than_12 = Mock(return_value=True)
+ mm.get_manager = Mock(return_value=tm)
+
+ results = mm.exec_module()
+
+ assert results['changed'] is True
+ assert results['name'] == 'foo.baz.bar'
+ assert results['state'] == 'present'
+ assert results['lb_method'] == 'round-robin'
+
+
+@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
+ return_value=True)
+class TestTypedManager(unittest.TestCase):
+
+ def setUp(self):
+ self.spec = ArgumentSpec()
+
+ def test_create_wideip(self, *args):
+ set_module_args(dict(
+ name='foo.baz.bar',
+ lb_method='round-robin',
+ type='a',
+ password='passsword',
+ server='localhost',
+ user='admin'
+ ))
+
+ client = AnsibleF5Client(
+ argument_spec=self.spec.argument_spec,
+ supports_check_mode=self.spec.supports_check_mode,
+ f5_product_name=self.spec.f5_product_name
+ )
+
+ # Override methods in the specific type of manager
+ tm = TypedManager(client)
+ tm.exists = Mock(return_value=False)
+ tm.create_on_device = Mock(return_value=True)
+
+ # Override methods to force specific logic in the module to happen
+ mm = ModuleManager(client)
+ mm.version_is_less_than_12 = Mock(return_value=False)
+ mm.get_manager = Mock(return_value=tm)
+
+ results = mm.exec_module()
+
+ assert results['changed'] is True
+ assert results['name'] == 'foo.baz.bar'
+ assert results['state'] == 'present'
+ assert results['lb_method'] == 'round-robin'
+
+ def test_create_wideip_deprecated_lb_method1(self, *args):
+ set_module_args(dict(
+ name='foo.baz.bar',
+ lb_method='round_robin',
+ type='a',
+ password='passsword',
+ server='localhost',
+ user='admin'
+ ))
+
+ client = AnsibleF5Client(
+ argument_spec=self.spec.argument_spec,
+ supports_check_mode=self.spec.supports_check_mode,
+ f5_product_name=self.spec.f5_product_name
+ )
+
+ # Override methods in the specific type of manager
+ tm = TypedManager(client)
+ tm.exists = Mock(return_value=False)
+ tm.create_on_device = Mock(return_value=True)
+
+ # Override methods to force specific logic in the module to happen
+ mm = ModuleManager(client)
+ mm.version_is_less_than_12 = Mock(return_value=False)
+ mm.get_manager = Mock(return_value=tm)
+
+ results = mm.exec_module()
+
+ assert results['changed'] is True
+ assert results['name'] == 'foo.baz.bar'
+ assert results['state'] == 'present'
+ assert results['lb_method'] == 'round-robin'
+
+ def test_create_wideip_deprecated_lb_method2(self, *args):
+ set_module_args(dict(
+ name='foo.baz.bar',
+ lb_method='global_availability',
+ type='a',
+ password='passsword',
+ server='localhost',
+ user='admin'
+ ))
+
+ client = AnsibleF5Client(
+ argument_spec=self.spec.argument_spec,
+ supports_check_mode=self.spec.supports_check_mode,
+ f5_product_name=self.spec.f5_product_name
+ )
+
+ # Override methods in the specific type of manager
+ tm = TypedManager(client)
+ tm.exists = Mock(return_value=False)
+ tm.create_on_device = Mock(return_value=True)
+
+ # Override methods to force specific logic in the module to happen
+ mm = ModuleManager(client)
+ mm.version_is_less_than_12 = Mock(return_value=False)
+ mm.get_manager = Mock(return_value=tm)
+
+ results = mm.exec_module()
+
+ assert results['changed'] is True
+ assert results['name'] == 'foo.baz.bar'
+ assert results['state'] == 'present'
+ assert results['lb_method'] == 'global-availability'