diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml
index 89be6c7ea4..dde465b72b 100644
--- a/.github/BOTMETA.yml
+++ b/.github/BOTMETA.yml
@@ -898,6 +898,14 @@ files:
labels:
- cloud
- openstack
+ contrib/inventory/infoblox.py:
+ keywords:
+ - infoblox dynamic inventory script
+ labels:
+ - ipam
+ - infoblox
+ - networking
+ maintainers: $team_networking
contrib/inventory/azure_rm.py:
keywords:
- azure inventory
diff --git a/contrib/inventory/infoblox.py b/contrib/inventory/infoblox.py
new file mode 100755
index 0000000000..374a7564d4
--- /dev/null
+++ b/contrib/inventory/infoblox.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# (c) 2018, Red Hat, 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 .
+#
+import os
+import sys
+import json
+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 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',
+ '/etc/ansible/infoblox.yml'
+]
+
+
+def parse_args():
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('--list', action='store_true',
+ help='List host records from NIOS for use in Ansible')
+
+ parser.add_argument('--host',
+ help='List meta data about single host (not used)')
+
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+
+ for config_file in CONFIG_FILES:
+ if os.path.exists(config_file):
+ break
+ else:
+ sys.stdout.write('unable to locate config file at /etc/ansible/infoblox.yaml\n')
+ sys.exit(-1)
+
+ try:
+ loader = DataLoader()
+ config = loader.load_from_file(config_file)
+ provider = config.get('provider') or {}
+ connector = get_connector(**provider)
+ except Exception as exc:
+ sys.stdout.write(to_text(exc))
+ sys.exit(-1)
+
+ if args.host:
+ host_filter = {'name': args.host}
+ else:
+ host_filter = {}
+
+ config_filters = config.get('filters')
+
+ if config_filters.get('view') is not None:
+ host_filter['view'] = config_filters['view']
+
+ if config_filters.get('extattrs'):
+ extattrs = normalize_extattrs(config_filters['extattrs'])
+ else:
+ extattrs = {}
+
+ hostvars = {}
+ inventory = {
+ '_meta': {
+ 'hostvars': hostvars
+ }
+ }
+
+ return_fields = ['name', 'view', 'extattrs', 'ipv4addrs']
+
+ hosts = connector.get_object('record:host',
+ host_filter,
+ extattrs=extattrs,
+ return_fields=return_fields)
+
+ if hosts:
+ for item in hosts:
+ view = item['view']
+ name = item['name']
+
+ if view not in inventory:
+ inventory[view] = {'hosts': []}
+
+ inventory[view]['hosts'].append(name)
+
+ hostvars[name] = {
+ 'view': view
+ }
+
+ if item.get('extattrs'):
+ for key, value in iteritems(flatten_extattrs(item['extattrs'])):
+ if key.startswith('ansible_'):
+ hostvars[name][key] = value
+ else:
+ if 'extattrs' not in hostvars:
+ hostvars[name]['extattrs'] = {}
+ hostvars[name]['extattrs'][key] = value
+
+ sys.stdout.write(json.dumps(inventory, indent=4))
+ sys.exit(0)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/inventory/infoblox.yaml b/contrib/inventory/infoblox.yaml
new file mode 100644
index 0000000000..c1be5324ac
--- /dev/null
+++ b/contrib/inventory/infoblox.yaml
@@ -0,0 +1,24 @@
+---
+# This file provides the configuration information for the Infoblox dynamic
+# inventory script that is used to dynamically pull host information from NIOS.
+# This file should be copied to /etc/ansible/infoblox.yaml in order for the
+# dynamic script to find it.
+
+# Sets the provider arguments for authenticating to the Infoblox server to
+# retrieve inventory hosts. Provider arguments can also be set using
+# environment variables. Supported environment variables all start with
+# INFOBLOX_{{ name }}. For instance, to set the host provider value, the
+# environment variable would be INFOBLOX_HOST.
+provider:
+ host:
+ username:
+ password:
+
+# Filters allow the dynamic inventory script to restrict the set of hosts that
+# are returned from the Infoblox server.
+filters:
+ # restrict returned hosts by extensible attributes
+ extattrs: {}
+
+ # restrict returned hosts to a specified DNS view
+ view: null
diff --git a/lib/ansible/module_utils/net_tools/nios/api.py b/lib/ansible/module_utils/net_tools/nios/api.py
index fd1689f011..8ecc3a450e 100644
--- a/lib/ansible/module_utils/net_tools/nios/api.py
+++ b/lib/ansible/module_utils/net_tools/nios/api.py
@@ -75,6 +75,43 @@ def get_connector(*args, **kwargs):
return Connector(kwargs)
+def normalize_extattrs(value):
+ ''' Normalize extattrs field to expected format
+
+ The module accepts extattrs as key/value pairs. This method will
+ transform the key/value pairs into a structure suitable for
+ sending across WAPI in the format of:
+
+ extattrs: {
+ key: {
+ value:
+ }
+ }
+ '''
+ return dict([(k, {'value': v}) for k, v in iteritems(value)])
+
+
+def flatten_extattrs(value):
+ ''' Flatten the key/value struct for extattrs
+
+ WAPI returns extattrs field as a dict in form of:
+
+ extattrs: {
+ key: {
+ value:
+ }
+ }
+
+ This method will flatten the structure to:
+
+ extattrs: {
+ key: value
+ }
+
+ '''
+ return dict([(k, v['value']) for k, v in iteritems(value)])
+
+
class WapiBase(object):
''' Base class for implementing Infoblox WAPI API '''
@@ -134,7 +171,7 @@ class Wapi(WapiBase):
if ib_obj:
current_object = ib_obj[0]
if 'extattrs' in current_object:
- current_object['extattrs'] = self.flatten_extattrs(current_object['extattrs'])
+ current_object['extattrs'] = flatten_extattrs(current_object['extattrs'])
ref = current_object.pop('_ref')
else:
current_object = obj_filter
@@ -151,7 +188,7 @@ class Wapi(WapiBase):
modified = not self.compare_objects(current_object, proposed_object)
if 'extattrs' in proposed_object:
- proposed_object['extattrs'] = self.normalize_extattrs(proposed_object['extattrs'])
+ proposed_object['extattrs'] = normalize_extattrs(proposed_object['extattrs'])
if state == 'present':
if ref is None:
@@ -206,41 +243,6 @@ class Wapi(WapiBase):
'it using nios_network_view first' % name)
return res
- def normalize_extattrs(self, value):
- ''' Normalize extattrs field to expected format
-
- The module accepts extattrs as key/value pairs. This method will
- transform the key/value pairs into a structure suitable for
- sending across WAPI in the format of:
-
- extattrs: {
- key: {
- value:
- }
- }
- '''
- return dict([(k, {'value': v}) for k, v in iteritems(value)])
-
- def flatten_extattrs(self, value):
- ''' Flatten the key/value struct for extattrs
-
- WAPI returns extattrs field as a dict in form of:
-
- extattrs: {
- key: {
- value:
- }
- }
-
- This method will flatten the structure to:
-
- extattrs: {
- key: value
- }
-
- '''
- return dict([(k, v['value']) for k, v in iteritems(value)])
-
def issubset(self, item, objects):
''' Checks if item is a subset of objects