diff --git a/lib/ansible/module_utils/net_tools/nios/api.py b/lib/ansible/module_utils/net_tools/nios/api.py index 06cc03bef97..fec4731c2d7 100644 --- a/lib/ansible/module_utils/net_tools/nios/api.py +++ b/lib/ansible/module_utils/net_tools/nios/api.py @@ -46,6 +46,8 @@ NIOS_HOST_RECORD = 'record:host' NIOS_IPV4_NETWORK = 'network' NIOS_IPV6_NETWORK = 'ipv6network' NIOS_ZONE = 'zone_auth' +NIOS_PTR_RECORD = 'record:ptr' + NIOS_PROVIDER_SPEC = { 'host': dict(), diff --git a/lib/ansible/modules/net_tools/nios/nios_ptr_record.py b/lib/ansible/modules/net_tools/nios/nios_ptr_record.py new file mode 100644 index 00000000000..08dc39df9c3 --- /dev/null +++ b/lib/ansible/modules/net_tools/nios/nios_ptr_record.py @@ -0,0 +1,159 @@ +#!/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_ptr_record +version_added: "2.7" +author: "Trebuchet Clement" +short_description: Configure Infoblox NIOS PTR records +description: + - Adds and/or removes instances of PTR record objects from + Infoblox NIOS servers. This module manages NIOS C(record:ptr) objects + using the Infoblox WAPI interface over REST. +requirements: + - infoblox_client +extends_documentation_fragment: nios +options: + name: + description: + - The name of the DNS PTR record in FQDN format to add or remove from + the system. + The field is required only for an PTR object in Forward Mapping Zone. + required: false + view: + description: + - Sets the DNS view to associate this a record with. The DNS + view must already be configured on the system + required: false + aliases: + - dns_view + ipv4addr: + description: + - The IPv4 Address of the record. Mutually exclusive with the ipv6addr. + required: true + aliases: + - ipv4 + ipv6addr: + description: + - The IPv6 Address of the record. Mutually exclusive with the ipv4addr. + required: true + aliases: + - ipv6 + ptrdname: + description: + - The domain name of the DNS PTR record in FQDN format. + required: true + ttl: + description: + - Time To Live (TTL) value for the record. + A 32-bit unsigned integer that represents the duration, in seconds, that the record is valid (cached). + Zero indicates that the record should not be cached. + 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. + 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. Maximum 256 characters. + 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. + default: present + choices: + - present + - absent +''' + +EXAMPLES = ''' +- name: Create a PTR Record + nios_ptr_record: + ipv4: 192.168.10.1 + ptrdname: host.ansible.com + state: present + provider: + host: "{{ inventory_hostname_short }}" + username: admin + password: admin + connection: local + +- name: Delete a PTR Record + nios_ptr_record: + ipv4: 192.168.10.1 + ptrdname: host.ansible.com + state: absent + provider: + host: "{{ inventory_hostname_short }}" + username: admin + password: admin + connection: local +''' + +RETURN = ''' # ''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.net_tools.nios.api import WapiModule +from ansible.module_utils.net_tools.nios.api import NIOS_PTR_RECORD + + +def main(): + # Module entry point + ib_spec = dict( + name=dict(required=False), + view=dict(aliases=['dns_view']), + ipv4addr=dict(aliases=['ipv4'], ib_req=True), + ipv6addr=dict(aliases=['ipv6'], ib_req=True), + ptrdname=dict(ib_req=True), + + 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(WapiModule.provider_spec) + + mutually_exclusive = [('ipv4addr', 'ipv6addr')] + required_one_of = [ + ['ipv4addr', 'ipv6addr'] + ] + + module = AnsibleModule(argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + required_one_of=required_one_of) + + if module.params['ipv4addr']: + del ib_spec['ipv6addr'] + elif module.params['ipv6addr']: + del ib_spec['ipv4addr'] + + wapi = WapiModule(module) + result = wapi.run(NIOS_PTR_RECORD, ib_spec) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/nios_ptr_record/aliases b/test/integration/targets/nios_ptr_record/aliases new file mode 100644 index 00000000000..a52e8b266f1 --- /dev/null +++ b/test/integration/targets/nios_ptr_record/aliases @@ -0,0 +1,3 @@ +posix/ci/cloud/group4/nios +cloud/nios +destructive diff --git a/test/integration/targets/nios_ptr_record/defaults/main.yaml b/test/integration/targets/nios_ptr_record/defaults/main.yaml new file mode 100644 index 00000000000..ebf6ffc9035 --- /dev/null +++ b/test/integration/targets/nios_ptr_record/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "*" +test_items: [] \ No newline at end of file diff --git a/test/integration/targets/nios_ptr_record/meta/main.yaml b/test/integration/targets/nios_ptr_record/meta/main.yaml new file mode 100644 index 00000000000..9472935b7cf --- /dev/null +++ b/test/integration/targets/nios_ptr_record/meta/main.yaml @@ -0,0 +1,2 @@ +dependencies: + - prepare_nios_tests \ No newline at end of file diff --git a/test/integration/targets/nios_ptr_record/tasks/main.yml b/test/integration/targets/nios_ptr_record/tasks/main.yml new file mode 100644 index 00000000000..ec33e8f537a --- /dev/null +++ b/test/integration/targets/nios_ptr_record/tasks/main.yml @@ -0,0 +1 @@ +- include: nios_ptr_record_idempotence.yml diff --git a/test/integration/targets/nios_ptr_record/tasks/nios_ptr_record_idempotence.yml b/test/integration/targets/nios_ptr_record/tasks/nios_ptr_record_idempotence.yml new file mode 100644 index 00000000000..64eccb9e51e --- /dev/null +++ b/test/integration/targets/nios_ptr_record/tasks/nios_ptr_record_idempotence.yml @@ -0,0 +1,78 @@ +--- + +- name: create an ipv4 ptr record + nios_ptr_record: + name: ptr.ansible.com + ptrdname: ptr.ansible.com + ipv4: 192.168.10.1 + state: present + provider: "{{ nios_provider }}" + view: default + register: ipv4_ptr_create1 + +- name: create the same ipv4 ptr record + nios_ptr_record: + name: ptr.ansible.com + ptrdname: ptr.ansible.com + ipv4: 192.168.10.1 + state: present + view: default + provider: "{{ nios_provider }}" + register: ipv4_ptr_create2 + +- name: add a comment to an existing ipv4 ptr record + nios_ptr_record: + name: ptr.ansible.com + ptrdname: ptr.ansible.com + ipv4: 192.168.10.1 + comment: this is a test comment + state: present + provider: "{{ nios_provider }}" + register: ipv4_ptr_update1 + +- name: add the same comment to the same ipv4 ptr host record + nios_ptr_record: + name: ptr.ansible.com + ptrdname: ptr.ansible.com + ipv4: 192.168.10.1 + comment: this is a test comment + state: present + provider: "{{ nios_provider }}" + register: ipv4_ptr_update2 + +- name: remove a ptr record from the system + nios_ptr_record: + name: ptr.ansible.com + ptrdname: ptr.ansible.com + ipv4: 192.168.10.1 + state: absent + provider: "{{ nios_provider }}" + register: ipv4_ptr_delete1 + +- name: remove the same ptr record from the system + nios_ptr_record: + ptrdname: ptr.ansible.com + name: ptr.ansible.com + ipv4: 192.168.10.1 + state: absent + provider: "{{ nios_provider }}" + register: ipv4_ptr_delete2 + +- name: create an ipv6 ptr record + nios_ptr_record: + ptrdname: ptr6.ansible.com + name: ptr6.ansible.com + ipv6: "2002:8ac3:802d:1242:20d:60ff:fe38:6d16" + state: present + provider: "{{ nios_provider }}" + register: ipv6_ptr_create1 + +- assert: + that: + - "ipv4_ptr_create1.changed" + - "not ipv4_ptr_create2.changed" + - "ipv4_ptr_update1.changed" + - "not ipv4_ptr_update2.changed" + - "ipv4_ptr_delete1.changed" + - "not ipv4_ptr_delete2.changed" + - "ipv6_ptr_create1.changed" diff --git a/test/units/modules/net_tools/nios/test_nios_ptr_record.py b/test/units/modules/net_tools/nios/test_nios_ptr_record.py new file mode 100644 index 00000000000..3a5d0ab6eb6 --- /dev/null +++ b/test/units/modules/net_tools/nios/test_nios_ptr_record.py @@ -0,0 +1,175 @@ +# 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 . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +from ansible.modules.net_tools.nios import nios_ptr_record +from ansible.module_utils.net_tools.nios import api +from ansible.compat.tests.mock import patch, MagicMock, Mock +from .test_nios_module import TestNiosModule, load_fixture + + +class TestNiosPTRRecordModule(TestNiosModule): + + module = nios_ptr_record + + def setUp(self): + + super(TestNiosPTRRecordModule, self).setUp() + self.module = MagicMock(name='ansible.modules.net_tools.nios.nios_ptr_record.WapiModule') + self.module.check_mode = False + self.module.params = {'provider': None} + + self.mock_wapi = patch('ansible.modules.net_tools.nios.nios_ptr_record.WapiModule') + self.exec_command = self.mock_wapi.start() + self.mock_wapi_run = patch('ansible.modules.net_tools.nios.nios_ptr_record.WapiModule.run') + self.mock_wapi_run.start() + + self.load_config = self.mock_wapi_run.start() + + def tearDown(self): + super(TestNiosPTRRecordModule, self).tearDown() + self.mock_wapi.stop() + + def _get_wapi(self, test_object): + 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') + wapi.delete_object = Mock(name='delete_object') + return wapi + + def load_fixtures(self, commands=None): + self.exec_command.return_value = (0, load_fixture('nios_result.txt').strip(), None) + self.load_config.return_value = dict(diff=None, session='session') + + def test_nios_ptr_record_create(self): + self.module.params = {'provider': None, 'state': 'present', 'ptrdname': 'ansible.test.com', + 'ipv4addr': '10.36.241.14', 'comment': None, 'extattrs': None} + + test_object = None + test_spec = { + "ipv4addr": {"ib_req": True}, + "ptrdname": {"ib_req": True}, + "comment": {}, + "extattrs": {} + } + + wapi = self._get_wapi(test_object) + print("WAPI: ", wapi) + res = wapi.run('testobject', test_spec) + + self.assertTrue(res['changed']) + wapi.create_object.assert_called_once_with('testobject', {'ipv4addr': '10.36.241.14', 'ptrdname': 'ansible.test.com'}) + + def test_nios_ptr_record_remove(self): + self.module.params = {'provider': None, 'state': 'absent', 'ptrdname': 'ansible.test.com', + 'ipv4addr': '10.36.241.14', 'comment': None, 'extattrs': None} + + ref = "record:ptr/ZG5zLm5ldHdvcmtfdmlldyQw:14.241.36.10.in-addr.arpa/default" + + test_object = [{ + "comment": "test comment", + "_ref": ref, + "ptrdname": "ansible.test.com", + "ipv4addr": "10.36.241.14", + "extattrs": {'Site': {'value': 'test'}} + }] + + test_spec = { + "ipv4addr": {"ib_req": True}, + "ptrdname": {"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_nios_ptr_record_update_comment(self): + self.module.params = {'provider': None, 'state': 'present', 'ptrdname': 'ansible.test.com', + 'ipv4addr': '10.36.241.14', 'comment': 'updated comment', 'extattrs': None} + + test_object = [ + { + "comment": "test comment", + "_ref": "record:ptr/ZG5zLm5ldHdvcmtfdmlldyQw:14.241.36.10.in-addr.arpa/default", + "ptrdname": "ansible.test.com", + "ipv4addr": "10.36.241.14", + "extattrs": {} + } + ] + + test_spec = { + "ipv4addr": {"ib_req": True}, + "ptrdname": {"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_nios_ptr_record_update_record_ptrdname(self): + self.module.params = {'provider': None, 'state': 'present', 'ptrdname': 'ansible.test.org', + 'ipv4addr': '10.36.241.14', 'comment': 'comment', 'extattrs': None} + + test_object = [ + { + "comment": "test comment", + "_ref": "record:ptr/ZG5zLm5ldHdvcmtfdmlldyQw:14.241.36.10.in-addr.arpa/default", + "ptrdname": "ansible.test.com", + "ipv4addr": "10.36.241.14", + "extattrs": {} + } + ] + + test_spec = { + "ipv4addr": {"ib_req": True}, + "ptrdname": {"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_nios_ptr6_record_create(self): + self.module.params = {'provider': None, 'state': 'present', 'ptrdname': 'ansible6.test.com', + 'ipv6addr': '2002:8ac3:802d:1242:20d:60ff:fe38:6d16', 'comment': None, 'extattrs': None} + + test_object = None + test_spec = {"ipv6addr": {"ib_req": True}, + "ptrdname": {"ib_req": True}, + "comment": {}, + "extattrs": {}} + + wapi = self._get_wapi(test_object) + print("WAPI: ", wapi) + res = wapi.run('testobject', test_spec) + + self.assertTrue(res['changed']) + wapi.create_object.assert_called_once_with('testobject', {'ipv6addr': '2002:8ac3:802d:1242:20d:60ff:fe38:6d16', 'ptrdname': 'ansible6.test.com'})