Repository: ansible/ansible

Issue:
ipa-dnsrecord: unable to support reverse DNS
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
ipa_dnsrecord

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
$ ansible --version
ansible 2.3.1.0
  config file = /Users/fxfitz/dev/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, May 18 2017, 22:52:22) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)]
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
N/A

##### SUMMARY
The new ipa_dnsrecord module (slated for release in 2.4; we've backported it for the time being) does not seem to support reverse DNS records at all.  While the A and AAAA record implementation appears to work great (thanks!), there doesn't seem to be any way to add a corresponding reverse record.

##### STEPS TO REPRODUCE
N/A

##### EXPECTED RESULTS
I expected to be able to do one of the following with the `ipa_dnsrecord` module:

1. (ideal) Have an option to be able to `reverse_dns_record: present` so the module will auto-create a reverse DNS record (similar to the FreeIPA Web UI).
2. Create the PTR record manually in the proper zone.

##### ACTUAL RESULTS
1. There was no option to automatically ensure a reverse_dns_record was present/absent.
2. You are unable to create a PTR record manually; only A and AAAA are supported.



Discussion:
cc @Nosmoht
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/identity/ipa/ipa_dnsrecord.py b/lib/ansible/modules/identity/ipa/ipa_dnsrecord.py
--- a/lib/ansible/modules/identity/ipa/ipa_dnsrecord.py
+++ b/lib/ansible/modules/identity/ipa/ipa_dnsrecord.py
@@ -45,13 +45,15 @@
   record_type:
     description:
     - The type of DNS record name
-    - Currently, 'A', 'AAAA' is supported
+    - Currently, 'A', 'AAAA', and 'PTR' are supported
     required: false
     default: 'A'
-    choices: ['A', 'AAAA']
-  record_ip:
+    choices: ['A', 'AAAA', 'PTR']
+  record_value:
     description:
-    - Manage DNS record name with this IP address.
+    - Manage DNS record name with this value.
+    - In the case of 'A' or 'AAAA' record types, this will be the IP address.
+    - In the case of 'PTR' record type, this will be the hostname.
     required: true
   state:
     description: State to ensure
@@ -97,14 +99,24 @@
     zone_name: example.com
     record_name: vm-001
     record_type: 'AAAA'
-    record_ip: '::1'
+    record_value: '::1'
+
+# Ensure a PTR record is present
+- ipa_dnsrecord:
+    ipa_host: spider.example.com
+    ipa_pass: Passw0rd!
+    state: present
+    zone_name: 2.168.192.in-addr.arpa
+    record_name: 5
+    record_type: 'PTR'
+    record_value: 'internal.ipa.example.com'
 
 # Ensure that dns record is removed
 - ipa_dnsrecord:
     name: host01
     zone_name: example.com
     record_type: 'AAAA'
-    record_ip: '::1'
+    record_value: '::1'
     ipa_host: ipa.example.com
     ipa_user: admin
     ipa_pass: topsecret
@@ -133,9 +145,11 @@ def dnsrecord_find(self, zone_name, record_name):
     def dnsrecord_add(self, zone_name=None, record_name=None, details=None):
         item = dict(idnsname=record_name)
         if details['record_type'] == 'A':
-            item.update(a_part_ip_address=details['record_ip'])
+            item.update(a_part_ip_address=details['record_value'])
         elif details['record_type'] == 'AAAA':
-            item.update(aaaa_part_ip_address=details['record_ip'])
+            item.update(aaaa_part_ip_address=details['record_value'])
+        elif details['record_type'] == 'PTR':
+            item.update(ptr_part_hostname=details['record_value'])
 
         return self._post_json(method='dnsrecord_add', name=zone_name, item=item)
 
@@ -152,10 +166,12 @@ def dnsrecord_del(self, zone_name=None, record_name=None, details=None):
 
 def get_dnsrecord_dict(details=None):
     module_dnsrecord = dict()
-    if details['record_type'] == 'A' and details['record_ip']:
-        module_dnsrecord.update(arecord=details['record_ip'])
-    elif details['record_type'] == 'AAAA' and details['record_ip']:
-        module_dnsrecord.update(aaaarecord=details['record_ip'])
+    if details['record_type'] == 'A' and details['record_value']:
+        module_dnsrecord.update(arecord=details['record_value'])
+    elif details['record_type'] == 'AAAA' and details['record_value']:
+        module_dnsrecord.update(aaaarecord=details['record_value'])
+    elif details['record_type'] == 'PTR' and details['record_value']:
+        module_dnsrecord.update(ptrrecord=details['record_value'])
     return module_dnsrecord
 
 
@@ -171,7 +187,7 @@ def ensure(module, client):
 
     ipa_dnsrecord = client.dnsrecord_find(zone_name, record_name)
     module_dnsrecord = dict(record_type=module.params['record_type'],
-                            record_ip=module.params['record_ip'])
+                            record_value=module.params['record_value'])
 
     changed = False
     if state == 'present':
@@ -201,13 +217,13 @@ def ensure(module, client):
 
 
 def main():
-    record_types = ['A', 'AAAA']
+    record_types = ['A', 'AAAA', 'PTR']
     module = AnsibleModule(
         argument_spec=dict(
             zone_name=dict(type='str', required=True),
             record_name=dict(type='str', required=True, aliases=['name']),
             record_type=dict(type='str', required=False, default='A', choices=record_types),
-            record_ip=dict(type='str', required=True),
+            record_value=dict(type='str', required=True),
             state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
             ipa_prot=dict(type='str', required=False, default='https', choices=['http', 'https']),
             ipa_host=dict(type='str', required=False, default='ipa.example.com'),


Test patch: