mirror of https://github.com/ansible/ansible.git
Add support for Infoblox NIOS (#35097)
* WIP: initial commit * update documentation in modules * fix up sanity check issues * add unit tests for nios api * fix up sanity check failures * fix up EXAMPLES in modules * mock infoblox_client.connector * remove unsupported assert statementpull/33735/head
parent
7228755f00
commit
8d775a332e
@ -0,0 +1,265 @@
|
|||||||
|
# This code is part of Ansible, but is an independent component.
|
||||||
|
# This particular file snippet, and this file snippet only, is BSD licensed.
|
||||||
|
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
||||||
|
# still belong to the author of the module, and may assign their own license
|
||||||
|
# to the complete work.
|
||||||
|
#
|
||||||
|
# (c) 2018 Red Hat Inc.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from ansible.module_utils.six import iteritems
|
||||||
|
|
||||||
|
try:
|
||||||
|
from infoblox_client.connector import Connector
|
||||||
|
from infoblox_client.exceptions import InfobloxException
|
||||||
|
HAS_INFOBLOX_CLIENT = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_INFOBLOX_CLIENT = False
|
||||||
|
|
||||||
|
|
||||||
|
nios_provider_spec = {
|
||||||
|
'host': dict(),
|
||||||
|
'username': dict(),
|
||||||
|
'password': dict(no_log=True),
|
||||||
|
'ssl_verify': dict(type='bool', default=False),
|
||||||
|
'http_request_timeout': dict(type='int', default=10),
|
||||||
|
'http_pool_connections': dict(type='int', default=10),
|
||||||
|
'http_pool_maxsize': dict(type='int', default=10),
|
||||||
|
'max_retries': dict(type='int', default=3),
|
||||||
|
'wapi_version': dict(default='1.4'),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_provider_spec():
|
||||||
|
return {'provider': dict(type='dict', options=nios_provider_spec)}
|
||||||
|
|
||||||
|
|
||||||
|
def get_connector(module):
|
||||||
|
if not HAS_INFOBLOX_CLIENT:
|
||||||
|
module.fail_json(msg='infoblox-client is required but does not appear '
|
||||||
|
'to be installed. It can be installed using the '
|
||||||
|
'command `pip install infoblox-client`')
|
||||||
|
return Connector(module.params['provider'])
|
||||||
|
|
||||||
|
|
||||||
|
class WapiBase(object):
|
||||||
|
''' Base class for implementing Infoblox WAPI API '''
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
self.module = module
|
||||||
|
self.connector = get_connector(module)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
try:
|
||||||
|
return self.__dict__[name]
|
||||||
|
except KeyError:
|
||||||
|
if name.startswith('_'):
|
||||||
|
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name))
|
||||||
|
return partial(self._invoke_method, name)
|
||||||
|
|
||||||
|
def _invoke_method(self, name, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
class Wapi(WapiBase):
|
||||||
|
''' Implements WapiBase for executing a NIOS module '''
|
||||||
|
|
||||||
|
def run(self, ib_obj_type, ib_spec):
|
||||||
|
''' Runs the module and performans configuration tasks
|
||||||
|
|
||||||
|
:args ib_obj_type: the WAPI object type to operate against
|
||||||
|
:args ib_spec: the specification for the WAPI object as a dict
|
||||||
|
|
||||||
|
:returns: a results dict
|
||||||
|
'''
|
||||||
|
state = self.module.params['state']
|
||||||
|
if state not in ('present', 'absent'):
|
||||||
|
self.module.fail_json(msg='state must be one of `present`, `absent`, got `%s`' % state)
|
||||||
|
|
||||||
|
result = {'changed': False}
|
||||||
|
|
||||||
|
obj_filter = dict([(k, self.module.params[k]) for k, v in iteritems(ib_spec) if v.get('ib_req')])
|
||||||
|
ib_obj = self.get_object(ib_obj_type, obj_filter.copy(), return_fields=ib_spec.keys())
|
||||||
|
|
||||||
|
if ib_obj:
|
||||||
|
current_object = ib_obj[0]
|
||||||
|
if 'extattrs' in current_object:
|
||||||
|
current_object['extattrs'] = self.flatten_extattrs(current_object['extattrs'])
|
||||||
|
ref = current_object.pop('_ref')
|
||||||
|
else:
|
||||||
|
current_object = obj_filter
|
||||||
|
ref = None
|
||||||
|
|
||||||
|
proposed_object = {}
|
||||||
|
for key, value in iteritems(ib_spec):
|
||||||
|
if self.module.params[key] is not None:
|
||||||
|
if 'transform' in value:
|
||||||
|
proposed_object[key] = value['transform'](self.module)
|
||||||
|
else:
|
||||||
|
proposed_object[key] = self.module.params[key]
|
||||||
|
|
||||||
|
modified = not self.compare_objects(current_object, proposed_object)
|
||||||
|
|
||||||
|
if 'extattrs' in proposed_object:
|
||||||
|
proposed_object['extattrs'] = self.normalize_extattrs(proposed_object['extattrs'])
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if ref is None:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
self.create_object(ib_obj_type, proposed_object)
|
||||||
|
result['changed'] = True
|
||||||
|
elif modified:
|
||||||
|
if 'network_view' in proposed_object:
|
||||||
|
self.check_if_network_view_exists(proposed_object['network_view'])
|
||||||
|
proposed_object.pop('network_view')
|
||||||
|
elif 'view' in proposed_object:
|
||||||
|
self.check_if_dns_view_exists(proposed_object['view'])
|
||||||
|
if not self.module.check_mode:
|
||||||
|
res = self.update_object(ref, proposed_object)
|
||||||
|
result['changed'] = True
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if ref is not None:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
self.delete_object(ref)
|
||||||
|
result['changed'] = True
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check_if_dns_view_exists(self, name, fail_on_missing=True):
|
||||||
|
''' Checks if the specified DNS view is already configured
|
||||||
|
|
||||||
|
:args name: the name of the DNS view to check
|
||||||
|
:args fail_on_missing: fail the module if the DNS view does not exist
|
||||||
|
|
||||||
|
:returns: True if the network_view exists and False if the DNS view
|
||||||
|
does not exist and fail_on_missing is False
|
||||||
|
'''
|
||||||
|
res = self.get_object('view', {'name': name}) is not None
|
||||||
|
if not res and fail_on_missing:
|
||||||
|
self.module.fail_json(msg='DNS view %s does not exist, please create '
|
||||||
|
'it using nios_dns_view first' % name)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def check_if_network_view_exists(self, name, fail_on_missing=True):
|
||||||
|
''' Checks if the specified network_view is already configured
|
||||||
|
|
||||||
|
:args name: the name of the network view to check
|
||||||
|
:args fail_on_missing: fail the module if the network_view does not exist
|
||||||
|
|
||||||
|
:returns: True if the network_view exists and False if the network_view
|
||||||
|
does not exist and fail_on_missing is False
|
||||||
|
'''
|
||||||
|
res = self.get_object('networkview', {'name': name}) is not None
|
||||||
|
if not res and fail_on_missing:
|
||||||
|
self.module.fail_json(msg='Network view %s does not exist, please create '
|
||||||
|
'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: <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: <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
|
||||||
|
|
||||||
|
:args item: the subset item to validate
|
||||||
|
:args objects: superset list of objects to validate against
|
||||||
|
|
||||||
|
:returns: True if item is a subset of one entry in objects otherwise
|
||||||
|
this method will return None
|
||||||
|
'''
|
||||||
|
for obj in objects:
|
||||||
|
if isinstance(item, dict):
|
||||||
|
if all(entry in obj.items() for entry in item.items()):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
if item in obj:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def compare_objects(self, current_object, proposed_object):
|
||||||
|
|
||||||
|
for key, proposed_item in iteritems(proposed_object):
|
||||||
|
current_item = current_object.get(key)
|
||||||
|
|
||||||
|
# if proposed has a key that current doesn't then the objects are
|
||||||
|
# not equal and False will be immediately returned
|
||||||
|
if current_item is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
elif isinstance(proposed_item, list):
|
||||||
|
for subitem in proposed_item:
|
||||||
|
if not self.issubset(subitem, current_item):
|
||||||
|
return False
|
||||||
|
|
||||||
|
elif isinstance(proposed_item, dict):
|
||||||
|
return self.compare_objects(current_item, proposed_item)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if current_item != proposed_item:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: nios_dns_view
|
||||||
|
version_added: "2.5"
|
||||||
|
author: "Peter Sprygada (@privateip)"
|
||||||
|
short_description: Configure Infoblox NIOS DNS views
|
||||||
|
description:
|
||||||
|
- Adds and/or removes instances of DNS view objects from
|
||||||
|
Infoblox NIOS servers. This module manages NIOS C(view) objects
|
||||||
|
using the Infoblox WAPI interface over REST.
|
||||||
|
requirements:
|
||||||
|
- infoblox_client
|
||||||
|
extends_documentation_fragment: nios
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Specifies the name of the DNS view to add and/or remove from the
|
||||||
|
system configuration based on the setting of the C(state) argument.
|
||||||
|
required: true
|
||||||
|
aliases:
|
||||||
|
- view
|
||||||
|
network_view:
|
||||||
|
description:
|
||||||
|
- Specifies the name of the network view to assign the configured
|
||||||
|
DNS view to. The network view must already be configured on the
|
||||||
|
target system.
|
||||||
|
required: true
|
||||||
|
default: default
|
||||||
|
extattrs:
|
||||||
|
description:
|
||||||
|
- Allows for the configuration of Extensible Attributes on the
|
||||||
|
instance of the object. This argument accepts a set of key / value
|
||||||
|
pairs for configuration.
|
||||||
|
required: false
|
||||||
|
comment:
|
||||||
|
description:
|
||||||
|
- Configures a text string comment to be associated with the instance
|
||||||
|
of this object. The provided text string will be configured on the
|
||||||
|
object instance.
|
||||||
|
required: false
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Configures the intended state of the instance of the object on
|
||||||
|
the NIOS server. When this value is set to C(present), the object
|
||||||
|
is configured on the device and when this value is set to C(absent)
|
||||||
|
the value is removed (if necessary) from the device.
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices:
|
||||||
|
- present
|
||||||
|
- absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: configure a new dns view instance
|
||||||
|
nios_dns_view:
|
||||||
|
name: ansible-dns
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: update the comment for dns view
|
||||||
|
nios_dns_view:
|
||||||
|
name: ansible-dns
|
||||||
|
comment: this is an example comment
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: remove the dns view instance
|
||||||
|
nios_dns_view:
|
||||||
|
name: ansible-dns
|
||||||
|
state: absent
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = ''' # '''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
''' Main entry point for module execution
|
||||||
|
'''
|
||||||
|
ib_spec = dict(
|
||||||
|
name=dict(required=True, aliases=['view'], ib_req=True),
|
||||||
|
network_view=dict(default='default', ib_req=True),
|
||||||
|
|
||||||
|
extattrs=dict(type='dict'),
|
||||||
|
comment=dict()
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec = dict(
|
||||||
|
provider=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec.update(ib_spec)
|
||||||
|
argument_spec.update(get_provider_spec())
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
wapi = Wapi(module)
|
||||||
|
result = wapi.run('view', ib_spec)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,219 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: nios_host_record
|
||||||
|
version_added: "2.5"
|
||||||
|
author: "Peter Sprygada (@privateip)"
|
||||||
|
short_description: Configure Infoblox NIOS host records
|
||||||
|
description:
|
||||||
|
- Adds and/or removes instances of host record objects from
|
||||||
|
Infoblox NIOS servers. This module manages NIOS C(record:host) objects
|
||||||
|
using the Infoblox WAPI interface over REST.
|
||||||
|
requirements:
|
||||||
|
- infoblox_client
|
||||||
|
extends_documentation_fragment: nios
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Specifies the fully qualified hostname to add or remove from
|
||||||
|
the system
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
view:
|
||||||
|
description:
|
||||||
|
- Sets the DNS view to associate this host record with. The DNS
|
||||||
|
view must already be configured on the system
|
||||||
|
required: true
|
||||||
|
default: default
|
||||||
|
aliases:
|
||||||
|
- dns_view
|
||||||
|
ipv4addrs:
|
||||||
|
description:
|
||||||
|
- Configures the IPv4 addresses for this host record. This argument
|
||||||
|
accepts a list of values (see suboptions)
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
aliases:
|
||||||
|
- ipv4
|
||||||
|
suboptions:
|
||||||
|
ipv4addr:
|
||||||
|
description:
|
||||||
|
- Configures the IPv4 address for the host record
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
aliases:
|
||||||
|
- address
|
||||||
|
mac:
|
||||||
|
description:
|
||||||
|
- Configures the hardware MAC address for the host record
|
||||||
|
required: false
|
||||||
|
ipv6addrs:
|
||||||
|
description:
|
||||||
|
- Configures the IPv6 addresses for the host record. This argument
|
||||||
|
accepts a list of values (see options)
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
aliases:
|
||||||
|
- ipv6
|
||||||
|
suboptions:
|
||||||
|
ipv6addr:
|
||||||
|
description:
|
||||||
|
- Configures the IPv6 address for the host record
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
aliases:
|
||||||
|
- address
|
||||||
|
ttl:
|
||||||
|
description:
|
||||||
|
- Configures the TTL to be associated with this host record
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
extattrs:
|
||||||
|
description:
|
||||||
|
- Allows for the configuration of Extensible Attributes on the
|
||||||
|
instance of the object. This argument accepts a set of key / value
|
||||||
|
pairs for configuration.
|
||||||
|
required: false
|
||||||
|
comment:
|
||||||
|
description:
|
||||||
|
- Configures a text string comment to be associated with the instance
|
||||||
|
of this object. The provided text string will be configured on the
|
||||||
|
object instance.
|
||||||
|
required: false
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Configures the intended state of the instance of the object on
|
||||||
|
the NIOS server. When this value is set to C(present), the object
|
||||||
|
is configured on the device and when this value is set to C(absent)
|
||||||
|
the value is removed (if necessary) from the device.
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices:
|
||||||
|
- present
|
||||||
|
- absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: configure an ipv4 host record
|
||||||
|
nios_host_record:
|
||||||
|
name: host.ansible.com
|
||||||
|
ipv4:
|
||||||
|
address: 192.168.10.1
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
- name: add a comment to an existing host record
|
||||||
|
nios_host_record:
|
||||||
|
name: host.ansible.com
|
||||||
|
ipv4:
|
||||||
|
address: 192.168.10.1
|
||||||
|
comment: this is a test comment
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: remove a host record from the system
|
||||||
|
nios_host_record:
|
||||||
|
name: host.ansible.com
|
||||||
|
state: absent
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
'''
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def ipaddr(module, key, filtered_keys=None):
|
||||||
|
''' Transforms the input value into a struct supported by WAPI
|
||||||
|
|
||||||
|
This function will transform the input from the playbook into a struct
|
||||||
|
that is valid for WAPI in the form of:
|
||||||
|
|
||||||
|
{
|
||||||
|
ipv4addr: <value>,
|
||||||
|
mac: <value>
|
||||||
|
}
|
||||||
|
|
||||||
|
This function does not validate the values are properly formatted or in
|
||||||
|
the acceptable range, that is left to WAPI.
|
||||||
|
'''
|
||||||
|
filtered_keys = filtered_keys or list()
|
||||||
|
objects = list()
|
||||||
|
for item in module.params[key]:
|
||||||
|
objects.append(dict([(k, v) for k, v in iteritems(item) if v is not None and k not in filtered_keys]))
|
||||||
|
return objects
|
||||||
|
|
||||||
|
|
||||||
|
def ipv4addrs(module):
|
||||||
|
return ipaddr(module, 'ipv4addrs', filtered_keys=['address'])
|
||||||
|
|
||||||
|
|
||||||
|
def ipv6addrs(module):
|
||||||
|
return ipaddr(module, 'ipv6addrs', filtered_keys=['address'])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
''' Main entry point for module execution
|
||||||
|
'''
|
||||||
|
ipv4addr_spec = dict(
|
||||||
|
ipv4addr=dict(required=True, aliases=['address'], ib_req=True),
|
||||||
|
mac=dict()
|
||||||
|
)
|
||||||
|
|
||||||
|
ipv6addr_spec = dict(
|
||||||
|
ipv6addr=dict(required=True, aliases=['address'], ib_req=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
ib_spec = dict(
|
||||||
|
name=dict(required=True, ib_req=True),
|
||||||
|
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||||
|
|
||||||
|
ipv4addrs=dict(type='list', aliases=['ipv4'], elements='dict', options=ipv4addr_spec, transform=ipv4addrs),
|
||||||
|
ipv6addrs=dict(type='list', aliases=['ipv6'], elements='dict', options=ipv6addr_spec, transform=ipv6addrs),
|
||||||
|
|
||||||
|
ttl=dict(type='int'),
|
||||||
|
|
||||||
|
extattrs=dict(type='dict'),
|
||||||
|
comment=dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec = dict(
|
||||||
|
provider=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec.update(ib_spec)
|
||||||
|
argument_spec.update(get_provider_spec())
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
wapi = Wapi(module)
|
||||||
|
result = wapi.run('record:host', ib_spec)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,215 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: nios_network
|
||||||
|
version_added: "2.5"
|
||||||
|
author: "Peter Sprygada (@privateip)"
|
||||||
|
short_description: Configure Infoblox NIOS network object
|
||||||
|
description:
|
||||||
|
- Adds and/or removes instances of network objects from
|
||||||
|
Infoblox NIOS servers. This module manages NIOS C(network) objects
|
||||||
|
using the Infoblox WAPI interface over REST.
|
||||||
|
requirements:
|
||||||
|
- infoblox_client
|
||||||
|
extends_documentation_fragment: nios
|
||||||
|
options:
|
||||||
|
network:
|
||||||
|
description:
|
||||||
|
- Specifies the network to add or remove from the system. The value
|
||||||
|
should use CIDR notation.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
aliases:
|
||||||
|
- name
|
||||||
|
- cidr
|
||||||
|
network_view:
|
||||||
|
description:
|
||||||
|
- Configures the name of the network view to associate with this
|
||||||
|
configured instance.
|
||||||
|
required: true
|
||||||
|
default: default
|
||||||
|
options:
|
||||||
|
description:
|
||||||
|
- Configures the set of DHCP options to be included as part of
|
||||||
|
the configured network instance. This argument accepts a list
|
||||||
|
of values (see suboptions). When configuring suboptions at
|
||||||
|
least one of C(name) or C(num) must be specified.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the DHCP option to configure
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
num:
|
||||||
|
description:
|
||||||
|
- The number of the DHCP option to configure
|
||||||
|
required: false
|
||||||
|
value:
|
||||||
|
description:
|
||||||
|
- The value of the DHCP option specified by C(name)
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
use_option:
|
||||||
|
description:
|
||||||
|
- Only applies to a subset of options (see NIOS API documentation)
|
||||||
|
required: false
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
vendor_class:
|
||||||
|
description:
|
||||||
|
- The name of the space this DHCP option is associated to
|
||||||
|
required: false
|
||||||
|
default: DHCP
|
||||||
|
extattrs:
|
||||||
|
description:
|
||||||
|
- Allows for the configuration of Extensible Attributes on the
|
||||||
|
instance of the object. This argument accepts a set of key / value
|
||||||
|
pairs for configuration.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
comment:
|
||||||
|
description:
|
||||||
|
- Configures a text string comment to be associated with the instance
|
||||||
|
of this object. The provided text string will be configured on the
|
||||||
|
object instance.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Configures the intended state of the instance of the object on
|
||||||
|
the NIOS server. When this value is set to C(present), the object
|
||||||
|
is configured on the device and when this value is set to C(absent)
|
||||||
|
the value is removed (if necessary) from the device.
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices:
|
||||||
|
- present
|
||||||
|
- absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: configure a network
|
||||||
|
nios_network:
|
||||||
|
network: 192.168.10.0/24
|
||||||
|
comment: this is a test comment
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: set dhcp options for a network
|
||||||
|
nios_network:
|
||||||
|
network: 192.168.10.0/24
|
||||||
|
comment: this is a test comment
|
||||||
|
options:
|
||||||
|
- name: domain-name
|
||||||
|
value: ansible.com
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: remove a network
|
||||||
|
nios_network:
|
||||||
|
network: 192.168.10.0/24
|
||||||
|
state: absent
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
'''
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def options(module):
|
||||||
|
''' Transforms the module argument into a valid WAPI struct
|
||||||
|
|
||||||
|
This function will transform the options argument into a structure that
|
||||||
|
is a valid WAPI structure in the format of:
|
||||||
|
|
||||||
|
{
|
||||||
|
name: <value>,
|
||||||
|
num: <value>,
|
||||||
|
value: <value>,
|
||||||
|
use_option: <value>,
|
||||||
|
vendor_class: <value>
|
||||||
|
}
|
||||||
|
|
||||||
|
It will remove any options that are set to None since WAPI will error on
|
||||||
|
that condition. It will also verify that either `name` or `num` is
|
||||||
|
set in the structure but does not validate the values are equal.
|
||||||
|
|
||||||
|
The remainder of the value validation is performed by WAPI
|
||||||
|
'''
|
||||||
|
options = list()
|
||||||
|
for item in module.params['options']:
|
||||||
|
opt = dict([(k, v) for k, v in iteritems(item) if v is not None])
|
||||||
|
if 'name' not in opt and 'num' not in opt:
|
||||||
|
module.fail_json(msg='one of `name` or `num` is required for option value')
|
||||||
|
options.append(opt)
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
''' Main entry point for module execution
|
||||||
|
'''
|
||||||
|
option_spec = dict(
|
||||||
|
# one of name or num is required; enforced by the function options()
|
||||||
|
name=dict(),
|
||||||
|
num=dict(type='int'),
|
||||||
|
|
||||||
|
value=dict(required=True),
|
||||||
|
|
||||||
|
use_option=dict(type='bool', default=True),
|
||||||
|
vendor_class=dict(default='DHCP')
|
||||||
|
)
|
||||||
|
|
||||||
|
ib_spec = dict(
|
||||||
|
network=dict(required=True, aliases=['name', 'cidr'], ib_req=True),
|
||||||
|
network_view=dict(default='default', ib_req=True),
|
||||||
|
|
||||||
|
options=dict(type='list', elements='dict', options=option_spec, transform=options),
|
||||||
|
|
||||||
|
extattrs=dict(type='dict'),
|
||||||
|
comment=dict()
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec = dict(
|
||||||
|
provider=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec.update(ib_spec)
|
||||||
|
argument_spec.update(get_provider_spec())
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
wapi = Wapi(module)
|
||||||
|
result = wapi.run('network', ib_spec)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: nios_network_view
|
||||||
|
version_added: "2.5"
|
||||||
|
author: "Peter Sprygada (@privateip)"
|
||||||
|
short_description: Configure Infoblox NIOS network views
|
||||||
|
description:
|
||||||
|
- Adds and/or removes instances of network view objects from
|
||||||
|
Infoblox NIOS servers. This module manages NIOS C(networkview) objects
|
||||||
|
using the Infoblox WAPI interface over REST.
|
||||||
|
requirements:
|
||||||
|
- infoblox_client
|
||||||
|
extends_documentation_fragment: nios
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Specifies the name of the network view to either add or remove
|
||||||
|
from the configuration.
|
||||||
|
required: true
|
||||||
|
aliases:
|
||||||
|
- network_view
|
||||||
|
extattrs:
|
||||||
|
description:
|
||||||
|
- Allows for the configuration of Extensible Attributes on the
|
||||||
|
instance of the object. This argument accepts a set of key / value
|
||||||
|
pairs for configuration.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
comment:
|
||||||
|
description:
|
||||||
|
- Configures a text string comment to be associated with the instance
|
||||||
|
of this object. The provided text string will be configured on the
|
||||||
|
object instance.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Configures the intended state of the instance of the object on
|
||||||
|
the NIOS server. When this value is set to C(present), the object
|
||||||
|
is configured on the device and when this value is set to C(absent)
|
||||||
|
the value is removed (if necessary) from the device.
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices:
|
||||||
|
- present
|
||||||
|
- absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: configure a new network view
|
||||||
|
nios_network_view:
|
||||||
|
name: ansible
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: update the comment for network view
|
||||||
|
nios_network_view:
|
||||||
|
name: ansible
|
||||||
|
comment: this is an example comment
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: remove the network view
|
||||||
|
nios_network_view:
|
||||||
|
name: ansible
|
||||||
|
state: absent
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = ''' # '''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
''' Main entry point for module execution
|
||||||
|
'''
|
||||||
|
ib_spec = dict(
|
||||||
|
name=dict(required=True, aliases=['network_view'], ib_req=True),
|
||||||
|
|
||||||
|
extattrs=dict(type='dict'),
|
||||||
|
comment=dict(),
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec = dict(
|
||||||
|
provider=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec.update(ib_spec)
|
||||||
|
argument_spec.update(get_provider_spec())
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
wapi = Wapi(module)
|
||||||
|
result = wapi.run('networkview', ib_spec)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: nios_zone
|
||||||
|
version_added: "2.5"
|
||||||
|
author: "Peter Sprygada (@privateip)"
|
||||||
|
short_description: Configure Infoblox NIOS DNS zones
|
||||||
|
description:
|
||||||
|
- Adds and/or removes instances of DNS zone objects from
|
||||||
|
Infoblox NIOS servers. This module manages NIOS C(zone_auth) objects
|
||||||
|
using the Infoblox WAPI interface over REST.
|
||||||
|
requirements:
|
||||||
|
- infoblox_client
|
||||||
|
extends_documentation_fragment: nios
|
||||||
|
options:
|
||||||
|
fqdn:
|
||||||
|
description:
|
||||||
|
- Specifies the qualified domain name to either add or remove from
|
||||||
|
the NIOS instance based on the configured C(state) value.
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
aliases:
|
||||||
|
- name
|
||||||
|
view:
|
||||||
|
description:
|
||||||
|
- Configures the DNS view name for the configured resource. The
|
||||||
|
specified DNS zone must already exist on the running NIOS instance
|
||||||
|
prior to configuring zones.
|
||||||
|
required: true
|
||||||
|
default: default
|
||||||
|
aliases:
|
||||||
|
- dns_view
|
||||||
|
grid_primary:
|
||||||
|
description:
|
||||||
|
- Configures the grid primary servers for this zone.
|
||||||
|
required: false
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the grid primary server
|
||||||
|
required: true
|
||||||
|
default: null
|
||||||
|
grid_secondaries:
|
||||||
|
description:
|
||||||
|
- Configures the grid secondary servers for this zone.
|
||||||
|
required: false
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the grid secondary server
|
||||||
|
required: true
|
||||||
|
extattrs:
|
||||||
|
description:
|
||||||
|
- Allows for the configuration of Extensible Attributes on the
|
||||||
|
instance of the object. This argument accepts a set of key / value
|
||||||
|
pairs for configuration.
|
||||||
|
required: false
|
||||||
|
comment:
|
||||||
|
description:
|
||||||
|
- Configures a text string comment to be associated with the instance
|
||||||
|
of this object. The provided text string will be configured on the
|
||||||
|
object instance.
|
||||||
|
required: false
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Configures the intended state of the instance of the object on
|
||||||
|
the NIOS server. When this value is set to C(present), the object
|
||||||
|
is configured on the device and when this value is set to C(absent)
|
||||||
|
the value is removed (if necessary) from the device.
|
||||||
|
required: false
|
||||||
|
default: present
|
||||||
|
choices:
|
||||||
|
- present
|
||||||
|
- absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: configure a zone on the system
|
||||||
|
nios_zone:
|
||||||
|
name: ansible.com
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: update the comment and ext attributes for an existing zone
|
||||||
|
nios_zone:
|
||||||
|
name: ansible.com
|
||||||
|
comment: this is an example comment
|
||||||
|
extattrs:
|
||||||
|
Site: west-dc
|
||||||
|
state: present
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
|
||||||
|
- name: remove the dns zone
|
||||||
|
nios_zone:
|
||||||
|
name: ansible.com
|
||||||
|
state: absent
|
||||||
|
provider:
|
||||||
|
host: "{{ inventory_hostname_short }}"
|
||||||
|
username: admin
|
||||||
|
password: admin
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = ''' # '''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.net_tools.nios.api import get_provider_spec, Wapi
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
''' Main entry point for module execution
|
||||||
|
'''
|
||||||
|
grid_spec = dict(
|
||||||
|
name=dict(required=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
ib_spec = dict(
|
||||||
|
fqdn=dict(required=True, aliases=['name'], ib_req=True),
|
||||||
|
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||||
|
|
||||||
|
grid_primary=dict(type='list', elements='dict', options=grid_spec),
|
||||||
|
grid_secondaries=dict(type='list', elements='dict', options=grid_spec),
|
||||||
|
|
||||||
|
extattrs=dict(type='dict'),
|
||||||
|
comment=dict()
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec = dict(
|
||||||
|
provider=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['present', 'absent'])
|
||||||
|
)
|
||||||
|
|
||||||
|
argument_spec.update(ib_spec)
|
||||||
|
argument_spec.update(get_provider_spec())
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
wapi = Wapi(module)
|
||||||
|
result = wapi.run('zone_auth', ib_spec)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,65 @@
|
|||||||
|
#
|
||||||
|
# (c) 2015, Peter Sprygada <psprygada@ansible.com>
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleDocFragment(object):
|
||||||
|
|
||||||
|
# Standard files documentation fragment
|
||||||
|
DOCUMENTATION = """
|
||||||
|
options:
|
||||||
|
provider:
|
||||||
|
description:
|
||||||
|
- A dict object containing connection details.
|
||||||
|
default: null
|
||||||
|
suboptions:
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- Specifies the DNS host name or address for connecting to the remote
|
||||||
|
instance of NIOS WAPI over REST
|
||||||
|
required: true
|
||||||
|
username:
|
||||||
|
description:
|
||||||
|
- Configures the username to use to authenticate the connection to
|
||||||
|
the remote instance of NIOS.
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- Specifies the password to use to authenticate the connection to
|
||||||
|
the remote instance of NIOS.
|
||||||
|
default: null
|
||||||
|
ssl_verify:
|
||||||
|
description:
|
||||||
|
- Boolean value to enable or disable verifying SSL certificates
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
http_request_timeout:
|
||||||
|
description:
|
||||||
|
- The amount of time before to wait before receiving a response
|
||||||
|
required: false
|
||||||
|
default: 10
|
||||||
|
max_retries:
|
||||||
|
description:
|
||||||
|
- Configures the number of attempted retries before the connection
|
||||||
|
is declared usable
|
||||||
|
required: false
|
||||||
|
default: 3
|
||||||
|
wapi_version:
|
||||||
|
description:
|
||||||
|
- Specifies the version of WAPI to use
|
||||||
|
required: false
|
||||||
|
default: 1.4
|
||||||
|
"""
|
@ -0,0 +1,230 @@
|
|||||||
|
# (c) 2018 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from ansible.compat.tests import unittest
|
||||||
|
from ansible.compat.tests.mock import patch, MagicMock, Mock
|
||||||
|
from ansible.module_utils.net_tools.nios import api
|
||||||
|
|
||||||
|
|
||||||
|
class TestNiosApi(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNiosApi, self).setUp()
|
||||||
|
|
||||||
|
self.module = MagicMock(name='AnsibleModule')
|
||||||
|
self.module.check_mode = False
|
||||||
|
self.module.params = {'provider': None}
|
||||||
|
|
||||||
|
self.mock_connector = patch('ansible.module_utils.net_tools.nios.api.get_connector')
|
||||||
|
self.mock_connector.start()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(TestNiosApi, self).tearDown()
|
||||||
|
|
||||||
|
self.mock_connector.stop()
|
||||||
|
|
||||||
|
def test_get_provider_spec(self):
|
||||||
|
provider_options = ['host', 'username', 'password', 'ssl_verify',
|
||||||
|
'http_request_timeout', 'http_pool_connections',
|
||||||
|
'http_pool_maxsize', 'max_retries', 'wapi_version']
|
||||||
|
res = api.get_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.get_object = Mock(name='get_object', return_value=test_object)
|
||||||
|
wapi.create_object = Mock(name='create_object')
|
||||||
|
wapi.update_object = Mock(name='update_object')
|
||||||
|
wapi.delete_object = Mock(name='delete_object')
|
||||||
|
return wapi
|
||||||
|
|
||||||
|
def test_wapi_no_change(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'present', 'name': 'default',
|
||||||
|
'comment': 'test comment', 'extattrs': None}
|
||||||
|
|
||||||
|
test_object = [
|
||||||
|
{
|
||||||
|
"comment": "test comment",
|
||||||
|
"_ref": "networkview/ZG5zLm5ldHdvcmtfdmlldyQw:default/true",
|
||||||
|
"name": "default",
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertFalse(res['changed'])
|
||||||
|
|
||||||
|
def test_wapi_change(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'present', 'name': 'default',
|
||||||
|
'comment': 'updated comment', 'extattrs': None}
|
||||||
|
|
||||||
|
test_object = [
|
||||||
|
{
|
||||||
|
"comment": "test comment",
|
||||||
|
"_ref": "networkview/ZG5zLm5ldHdvcmtfdmlldyQw:default/true",
|
||||||
|
"name": "default",
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertTrue(res['changed'])
|
||||||
|
wapi.update_object.called_once_with(test_object)
|
||||||
|
|
||||||
|
def test_wapi_extattrs_change(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'present', 'name': 'default',
|
||||||
|
'comment': 'test comment', 'extattrs': {'Site': 'update'}}
|
||||||
|
|
||||||
|
ref = "networkview/ZG5zLm5ldHdvcmtfdmlldyQw:default/true"
|
||||||
|
|
||||||
|
test_object = [{
|
||||||
|
"comment": "test comment",
|
||||||
|
"_ref": ref,
|
||||||
|
"name": "default",
|
||||||
|
"extattrs": {'Site': {'value': 'test'}}
|
||||||
|
}]
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
kwargs = copy.deepcopy(test_object[0])
|
||||||
|
kwargs['extattrs']['Site']['value'] = 'update'
|
||||||
|
del kwargs['_ref']
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertTrue(res['changed'])
|
||||||
|
wapi.update_object.assert_called_once_with(ref, kwargs)
|
||||||
|
|
||||||
|
def test_wapi_extattrs_nochange(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'present', 'name': 'default',
|
||||||
|
'comment': 'test comment', 'extattrs': {'Site': 'test'}}
|
||||||
|
|
||||||
|
test_object = [{
|
||||||
|
"comment": "test comment",
|
||||||
|
"_ref": "networkview/ZG5zLm5ldHdvcmtfdmlldyQw:default/true",
|
||||||
|
"name": "default",
|
||||||
|
"extattrs": {'Site': {'value': 'test'}}
|
||||||
|
}]
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertFalse(res['changed'])
|
||||||
|
|
||||||
|
def test_wapi_create(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'present', 'name': 'ansible',
|
||||||
|
'comment': None, 'extattrs': None}
|
||||||
|
|
||||||
|
test_object = None
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertTrue(res['changed'])
|
||||||
|
wapi.create_object.assert_called_once_with('testobject', {'name': 'ansible'})
|
||||||
|
|
||||||
|
def test_wapi_delete(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'absent', 'name': 'ansible',
|
||||||
|
'comment': None, 'extattrs': None}
|
||||||
|
|
||||||
|
ref = "networkview/ZG5zLm5ldHdvcmtfdmlldyQw:ansible/false"
|
||||||
|
|
||||||
|
test_object = [{
|
||||||
|
"comment": "test comment",
|
||||||
|
"_ref": ref,
|
||||||
|
"name": "ansible",
|
||||||
|
"extattrs": {'Site': {'value': 'test'}}
|
||||||
|
}]
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertTrue(res['changed'])
|
||||||
|
wapi.delete_object.assert_called_once_with(ref)
|
||||||
|
|
||||||
|
def test_wapi_strip_network_view(self):
|
||||||
|
self.module.params = {'provider': None, 'state': 'present', 'name': 'ansible',
|
||||||
|
'comment': 'updated comment', 'extattrs': None,
|
||||||
|
'network_view': 'default'}
|
||||||
|
|
||||||
|
test_object = [{
|
||||||
|
"comment": "test comment",
|
||||||
|
"_ref": "view/ZG5zLm5ldHdvcmtfdmlldyQw:ansible/true",
|
||||||
|
"name": "ansible",
|
||||||
|
"extattrs": {},
|
||||||
|
"network_view": "default"
|
||||||
|
}]
|
||||||
|
|
||||||
|
test_spec = {
|
||||||
|
"name": {"ib_req": True},
|
||||||
|
"network_view": {"ib_req": True},
|
||||||
|
"comment": {},
|
||||||
|
"extattrs": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
kwargs = test_object[0].copy()
|
||||||
|
ref = kwargs.pop('_ref')
|
||||||
|
kwargs['comment'] = 'updated comment'
|
||||||
|
del kwargs['network_view']
|
||||||
|
del kwargs['extattrs']
|
||||||
|
|
||||||
|
wapi = self._get_wapi(test_object)
|
||||||
|
res = wapi.run('testobject', test_spec)
|
||||||
|
|
||||||
|
self.assertTrue(res['changed'])
|
||||||
|
wapi.update_object.assert_called_once_with(ref, kwargs)
|
Loading…
Reference in New Issue