diff --git a/contrib/inventory/infoblox.py b/contrib/inventory/infoblox.py index 374a7564d4..736333faf1 100755 --- a/contrib/inventory/infoblox.py +++ b/contrib/inventory/infoblox.py @@ -25,18 +25,9 @@ import argparse from ansible.parsing.dataloader import DataLoader from ansible.module_utils.six import iteritems from ansible.module_utils._text import to_text -from ansible.module_utils.net_tools.nios.api import get_connector +from ansible.module_utils.net_tools.nios.api import WapiInventory from ansible.module_utils.net_tools.nios.api import normalize_extattrs, flatten_extattrs -try: - # disable urllib3 warnings so as to not interfere with printing to stdout - # which is read by ansible - import urllib3 - urllib3.disable_warnings() -except ImportError: - sys.stdout.write('missing required library: urllib3\n') - sys.exit(-1) - CONFIG_FILES = [ '/etc/ansible/infoblox.yaml', @@ -70,7 +61,7 @@ def main(): loader = DataLoader() config = loader.load_from_file(config_file) provider = config.get('provider') or {} - connector = get_connector(**provider) + wapi = WapiInventory(provider) except Exception as exc: sys.stdout.write(to_text(exc)) sys.exit(-1) @@ -99,10 +90,10 @@ def main(): return_fields = ['name', 'view', 'extattrs', 'ipv4addrs'] - hosts = connector.get_object('record:host', - host_filter, - extattrs=extattrs, - return_fields=return_fields) + hosts = wapi.get_object('record:host', + host_filter, + extattrs=extattrs, + return_fields=return_fields) if hosts: for item in hosts: diff --git a/lib/ansible/module_utils/net_tools/nios/api.py b/lib/ansible/module_utils/net_tools/nios/api.py index 8ecc3a450e..83be2b8794 100644 --- a/lib/ansible/module_utils/net_tools/nios/api.py +++ b/lib/ansible/module_utils/net_tools/nios/api.py @@ -45,6 +45,7 @@ nios_provider_spec = { 'username': dict(), 'password': dict(no_log=True), 'ssl_verify': dict(type='bool', default=False), + 'silent_ssl_warnings': dict(type='bool', default=True), 'http_request_timeout': dict(type='int', default=10), 'http_pool_connections': dict(type='int', default=10), 'http_pool_maxsize': dict(type='int', default=10), @@ -53,11 +54,14 @@ nios_provider_spec = { } -def get_provider_spec(): - return {'provider': dict(type='dict', options=nios_provider_spec)} - - def get_connector(*args, **kwargs): + ''' Returns an instance of infoblox_client.connector.Connector + + :params args: positional arguments are silently ignored + :params kwargs: dict that is passed to Connector init + + :returns: Connector + ''' if not HAS_INFOBLOX_CLIENT: raise Exception('infoblox-client is required but does not appear ' 'to be installed. It can be installed using the ' @@ -66,8 +70,15 @@ def get_connector(*args, **kwargs): if not set(kwargs.keys()).issubset(nios_provider_spec.keys()): raise Exception('invalid or unsupported keyword argument for connector') - for key in nios_provider_spec.keys(): + for key, value in iteritems(nios_provider_spec): if key not in kwargs: + # apply default values from nios_provider_spec since we cannot just + # assume the provider values are coming from AnsibleModule + if 'default' in value: + kwargs[key] = value['default'] + + # override any values with env variables unless they were + # explicitly set env = ('INFOBLOX_%s' % key).upper() if env in os.environ: kwargs[key] = os.environ.get(env) @@ -115,14 +126,10 @@ def flatten_extattrs(value): class WapiBase(object): ''' Base class for implementing Infoblox WAPI API ''' - def __init__(self, module): - self.module = module + provider_spec = {'provider': dict(type='dict', options=nios_provider_spec)} - try: - provider = module.params['provider'] or {} - self.connector = get_connector(**provider) - except Exception as exc: - module.fail_json(msg=to_text(exc)) + def __init__(self, provider): + self.connector = get_connector(**provider) def __getattr__(self, name): try: @@ -137,20 +144,50 @@ class WapiBase(object): method = getattr(self.connector, name) return method(*args, **kwargs) except InfobloxException as exc: - self.module.fail_json( - msg=exc.response['text'], - type=exc.response['Error'].split(':')[0], - code=exc.response.get('code'), - action=name - ) - - def run(self, ib_obj_type, ib_spec): - raise NotImplementedError + if hasattr(self, 'handle_exception'): + self.handle_exception(name, exc) + else: + raise -class Wapi(WapiBase): +class WapiLookup(WapiBase): + ''' Implements WapiBase for lookup plugins ''' + pass + + +class WapiInventory(WapiBase): + ''' Implements WapiBase for dynamic inventory script ''' + pass + + +class WapiModule(WapiBase): ''' Implements WapiBase for executing a NIOS module ''' + def __init__(self, module): + self.module = module + provider = module.params['provider'] + + try: + super(WapiModule, self).__init__(provider) + except Exception as exc: + self.module.fail_json(msg=to_text(exc)) + + def handle_exception(self, method_name, exc): + ''' Handles any exceptions raised + + This method will be called if an InfobloxException is raised for + any call to the instance of Connector. This method will then + gracefully fail the module. + + :args exc: instance of InfobloxException + ''' + self.module.fail_json( + msg=exc.response['text'], + type=exc.response['Error'].split(':')[0], + code=exc.response.get('code'), + operation=method_name + ) + def run(self, ib_obj_type, ib_spec): ''' Runs the module and performans configuration tasks diff --git a/lib/ansible/modules/net_tools/nios/nios_dns_view.py b/lib/ansible/modules/net_tools/nios/nios_dns_view.py index 154d43e296..edd895d3b8 100644 --- a/lib/ansible/modules/net_tools/nios/nios_dns_view.py +++ b/lib/ansible/modules/net_tools/nios/nios_dns_view.py @@ -96,7 +96,7 @@ EXAMPLES = ''' RETURN = ''' # ''' from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi +from ansible.module_utils.net_tools.nios.api import WapiModule def main(): @@ -116,12 +116,12 @@ def main(): ) argument_spec.update(ib_spec) - argument_spec.update(get_provider_spec()) + argument_spec.update(WapiModule.provider_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - wapi = Wapi(module) + wapi = WapiModule(module) result = wapi.run('view', ib_spec) module.exit_json(**result) diff --git a/lib/ansible/modules/net_tools/nios/nios_host_record.py b/lib/ansible/modules/net_tools/nios/nios_host_record.py index 00e741cf14..d226710720 100644 --- a/lib/ansible/modules/net_tools/nios/nios_host_record.py +++ b/lib/ansible/modules/net_tools/nios/nios_host_record.py @@ -141,7 +141,7 @@ RETURN = ''' # ''' from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import iteritems -from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi +from ansible.module_utils.net_tools.nios.api import WapiModule def ipaddr(module, key, filtered_keys=None): @@ -204,12 +204,12 @@ def main(): ) argument_spec.update(ib_spec) - argument_spec.update(get_provider_spec()) + argument_spec.update(WapiModule.provider_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - wapi = Wapi(module) + wapi = WapiModule(module) result = wapi.run('record:host', ib_spec) module.exit_json(**result) diff --git a/lib/ansible/modules/net_tools/nios/nios_network.py b/lib/ansible/modules/net_tools/nios/nios_network.py index a7e9f48f4d..b3e36d109f 100644 --- a/lib/ansible/modules/net_tools/nios/nios_network.py +++ b/lib/ansible/modules/net_tools/nios/nios_network.py @@ -138,7 +138,7 @@ RETURN = ''' # ''' from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import iteritems -from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi +from ansible.module_utils.net_tools.nios.api import WapiModule def options(module): @@ -200,12 +200,12 @@ def main(): ) argument_spec.update(ib_spec) - argument_spec.update(get_provider_spec()) + argument_spec.update(WapiModule.provider_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - wapi = Wapi(module) + wapi = WapiModule(module) result = wapi.run('network', ib_spec) module.exit_json(**result) diff --git a/lib/ansible/modules/net_tools/nios/nios_network_view.py b/lib/ansible/modules/net_tools/nios/nios_network_view.py index 3efcf5e466..fa7a9f87d3 100644 --- a/lib/ansible/modules/net_tools/nios/nios_network_view.py +++ b/lib/ansible/modules/net_tools/nios/nios_network_view.py @@ -91,7 +91,7 @@ EXAMPLES = ''' RETURN = ''' # ''' from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi +from ansible.module_utils.net_tools.nios.api import WapiModule def main(): @@ -110,12 +110,12 @@ def main(): ) argument_spec.update(ib_spec) - argument_spec.update(get_provider_spec()) + argument_spec.update(WapiModule.provider_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - wapi = Wapi(module) + wapi = WapiModule(module) result = wapi.run('networkview', ib_spec) module.exit_json(**result) diff --git a/lib/ansible/modules/net_tools/nios/nios_zone.py b/lib/ansible/modules/net_tools/nios/nios_zone.py index 14e7dbfb78..3fd6fbf18b 100644 --- a/lib/ansible/modules/net_tools/nios/nios_zone.py +++ b/lib/ansible/modules/net_tools/nios/nios_zone.py @@ -128,7 +128,7 @@ EXAMPLES = ''' RETURN = ''' # ''' from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi +from ansible.module_utils.net_tools.nios.api import WapiModule def main(): @@ -157,12 +157,12 @@ def main(): ) argument_spec.update(ib_spec) - argument_spec.update(get_provider_spec()) + argument_spec.update(WapiModule.provider_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - wapi = Wapi(module) + wapi = WapiModule(module) result = wapi.run('zone_auth', ib_spec) module.exit_json(**result) diff --git a/lib/ansible/plugins/lookup/nios.py b/lib/ansible/plugins/lookup/nios.py index e545f25fb8..761ff8c408 100644 --- a/lib/ansible/plugins/lookup/nios.py +++ b/lib/ansible/plugins/lookup/nios.py @@ -95,8 +95,7 @@ obj_type: """ from ansible.plugins.lookup import LookupBase -from ansible.module_utils.net_tools.nios.api import nios_provider_spec -from ansible.module_utils.net_tools.nios.api import get_connector +from ansible.module_utils.net_tools.nios.api import WapiLookup from ansible.module_utils.net_tools.nios.api import normalize_extattrs, flatten_extattrs from ansible.errors import AnsibleError @@ -113,8 +112,8 @@ class LookupModule(LookupBase): filter_data = kwargs.pop('filter', {}) extattrs = normalize_extattrs(kwargs.pop('extattrs', {})) provider = kwargs.pop('provider', {}) - connector = get_connector(**provider) - res = connector.get_object(obj_type, filter_data, return_fields=return_fields) + wapi = WapiLookup(provider) + res = wapi.get_object(obj_type, filter_data, return_fields=return_fields) for obj in res: if 'extattrs' in obj: obj['extattrs'] = flatten_extattrs(obj['extattrs']) diff --git a/lib/ansible/plugins/lookup/nios_next_ip.py b/lib/ansible/plugins/lookup/nios_next_ip.py index adfe1e7a2c..026003ce1e 100644 --- a/lib/ansible/plugins/lookup/nios_next_ip.py +++ b/lib/ansible/plugins/lookup/nios_next_ip.py @@ -60,8 +60,7 @@ _list: """ from ansible.plugins.lookup import LookupBase -from ansible.module_utils.net_tools.nios.api import nios_provider_spec -from ansible.module_utils.net_tools.nios.api import get_connector +from ansible.module_utils.net_tools.nios.api import WapiLookup from ansible.module_utils._text import to_text from ansible.errors import AnsibleError @@ -75,9 +74,9 @@ class LookupModule(LookupBase): raise AnsibleError('missing argument in the form of A.B.C.D/E') provider = kwargs.pop('provider', {}) - connector = get_connector(**provider) + wapi = WapiLookup(provider) - network_obj = connector.get_object('network', {'network': network}) + network_obj = wapi.get_object('network', {'network': network}) if network_obj is None: raise AnsibleError('unable to find network object %s' % network) @@ -85,7 +84,7 @@ class LookupModule(LookupBase): try: ref = network_obj[0]['_ref'] - avail_ips = connector.call_func('next_available_ip', ref, {'num': num}) + avail_ips = wapi.call_func('next_available_ip', ref, {'num': num}) return [avail_ips['ips']] except Exception as exc: raise AnsibleError(to_text(exc)) diff --git a/test/units/module_utils/net_tools/nios/test_api.py b/test/units/module_utils/net_tools/nios/test_api.py index 7e65046a2d..a93d4b3ac8 100644 --- a/test/units/module_utils/net_tools/nios/test_api.py +++ b/test/units/module_utils/net_tools/nios/test_api.py @@ -30,24 +30,18 @@ class TestNiosApi(unittest.TestCase): self.mock_connector.stop() def test_get_provider_spec(self): - provider_options = ['host', 'username', 'password', 'ssl_verify', + provider_options = ['host', 'username', 'password', 'ssl_verify', 'silent_ssl_warnings', 'http_request_timeout', 'http_pool_connections', 'http_pool_maxsize', 'max_retries', 'wapi_version'] - res = api.get_provider_spec() + res = api.WapiBase.provider_spec self.assertIsNotNone(res) self.assertIn('provider', res) self.assertIn('options', res['provider']) returned_options = res['provider']['options'] self.assertEqual(sorted(provider_options), sorted(returned_options.keys())) - def test_wapi_base(self): - wapi = api.WapiBase(self.module) - - with self.assertRaises(NotImplementedError): - wapi.run(None, None) - def _get_wapi(self, test_object): - wapi = api.Wapi(self.module) + wapi = api.WapiModule(self.module) wapi.get_object = Mock(name='get_object', return_value=test_object) wapi.create_object = Mock(name='create_object') wapi.update_object = Mock(name='update_object')