diff --git a/README-dnsrecord.md b/README-dnsrecord.md new file mode 100644 index 0000000000000000000000000000000000000000..6f88f4322cebfbc893b75dde71b31c8c959e1c71 --- /dev/null +++ b/README-dnsrecord.md @@ -0,0 +1,357 @@ +DNSRecord module +================ + +Description +----------- + +The dnsrecord module allows management of DNS records and is as compatible as possible with the Ansible upstream `ipa_dnsrecord` module, but provide some other features like multiple record management in one execution and support for more DNS record types. + + +Features +-------- +* DNS record management. + + +Supported FreeIPA Versions +-------------------------- + +FreeIPA versions 4.4.0 and up are supported by the ipadnsrecord module. + + +Requirements +------------ + +**Controller** +* Ansible version: 2.8+ + +**Node** +* Supported FreeIPA version (see above) + + +Usage +===== + +Example inventory file + +```ini +[ipaserver] +ipaserver.example.com +``` + +Example playbook to ensure an AAAA record is present: + +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' +``` + +Example playbook to ensure an AAAA record is present, with a TTL of 300: + +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' + record_ttl: 300 +``` + +Example playbook to ensure an AAAA record is present, with a reverse PTR record: +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host02 + zone_name: example.com + record_type: 'AAAA' + record_value: 'fd00::0002' + create_reverse: yes +``` + +Example playbook to ensure a LOC record is present, given its individual attributes: +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host03 + loc_lat_deg: 52 + loc_lat_min: 22 + loc_lat_sec: 23.000 + loc_lat_dir: N + loc_lon_deg: 4 + loc_lon_min: 53 + loc_lon_sec: 32.00 + loc_lon_dir: E + loc_altitude: -2.00 + loc_size: 1.00 + loc_h_precision: 10000 + loc_v_precision: 10 +``` + +Example playbook to ensure multiple DNS records are present: + +```yaml +--- +ipadnsrecord: + ipaadmin_password: SomeADMINpassword + records: + - name: host02 + zone_name: example.com + record_type: A + record_value: + - "{{ ipv4_prefix }}.112" + - "{{ ipv4_prefix }}.122" + - name: host02 + zone_name: example.com + record_type: AAAA + record_value: ::1 +``` + +Example playbook to ensure multiple CNAME records are present: + +```yaml +--- +- name: Ensure that 'host03' and 'host04' have CNAME records. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + records: + - name: host03 + cname_hostname: host03.example.com + - name: host04 + cname_hostname: host04.example.com +``` + +Example playbook to ensure NS record is absent: + +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host04 + ns_hostname: host04 + state: absent +``` + +Example playbook to ensure LOC record is present, with fields: + +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host04 + loc_lat_deg: 52 + loc_lat_min: 22 + loc_lat_sec: 23.000 + loc_lat_dir: N + loc_lon_deg: 4 + loc_lon_min: 53 + loc_lon_sec: 32.000 + loc_lon_dir: E + loc_altitude: -2.00 + loc_size: 0.00 + loc_h_precision: 10000 + loc_v_precision: 10 +``` + +Change value of an existing LOC record: + +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host04 + loc_size: 1.00 + loc_rec: 52 22 23 N 4 53 32 E -2 0 10000 10 +``` + +Example playbook to ensure multiple A records are present: + +```yaml +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host04 + a_rec: + - 192.168.122.221 + - 192.168.122.222 + - 192.168.122.223 + - 192.168.122.224 +``` + +Example playbook to ensure A and AAAA records are present, with reverse records (PTR): +```yaml +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host01 + a_rec: + - 192.168.122.221 + - 192.168.122.222 + aaaa_rec: + - fd00:;0001 + - fd00::0002 + create_reverse: yes +``` + +Example playbook to ensure multiple A and AAAA records are present, but only A records have reverse records: +```yaml +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host01 + a_ip_address: 192.168.122.221 + aaaa_ip_address: fd00::0001 + a_create_reverse: yes +``` + +Example playbook to ensure multiple DNS records are absent: + +```yaml +--- +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + records: + - name: host01 + del_all: yes + - name: host02 + del_all: yes + - name: host03 + del_all: yes + - name: host04 + del_all: yes + - name: _ftp._tcp + del_all: yes + - name: _sip._udp + del_all: yes + state: absent +``` + +Variables +========= + +ipadnsrecord +------------ + +Variable | Description | Required +-------- | ----------- | -------- +`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no +`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no +`zone_name` \| `dnszone` | The DNS zone name to which DNS record needs to be managed. You can use one global zone name for multiple records. | no + required: true +`records` | The list of dns records dicts. Each `records` dict entry can contain **record variables**. | no + | **Record variables** | no +**Record variables** | Used when defining a single record. | no +`state` | The state to ensure. It can be one of `present` or `absent`, and defaults to `present`. | yes + + +**Record Variables:** + +Variable | Description | Required +-------- | ----------- | -------- +`zone_name` \| `dnszone` | The DNS zone name to which DNS record needs to be managed. You can use one global zone name for multiple records. When used on a `records` dict, overrides the global `zone_name`. | yes +`name` \| `record_name` | The DNS record name to manage. | yes +`record_type` | The type of DNS record. Supported values are `A`, `AAAA`, `A6`, `AFSDB`, `CERT`, `CNAME`, `DLV`, `DNAME`, `DS`, `KX`, `LOC`, `MX`, `NAPTR`, `NS`, `PTR`, `SRV`, `SSHFP`, `TLSA`, `TXT`, `URI`, and defaults to `A`. | no +`record_value` | Manage DNS record name with this values. | no +`record_ttl` | Set the TTL for the record. (int) | no +`del_all` | Delete all associated records. (bool) | no +`a_rec` \| `a_record` | Raw A record. | no +`aaaa_rec` \| `aaaa_record` | Raw AAAA record. | no +`a6_rec` \| `a6_record` | Raw A6 record data. | no +`afsdb_rec` \| `afsdb_record` | Raw AFSDB record. | no +`cert_rec` \| `cert_record` | Raw CERT record. | no +`cname_rec` \| `cname_record` | Raw CNAME record. | no +`dlv_rec` \| `dlv_record` | Raw DLV record. | no +`dname_rec` \| `dname_record` | Raw DNAM record. | no +`ds_rec` \| `ds_record` | Raw DS record. | no +`kx_rec` \| `kx_record` | Raw KX record. | no +`loc_rec` \| `loc_record` | Raw LOC record. | no +`mx_rec` \| `mx_record` | Raw MX record. | no +`naptr_rec` \| `naptr_record` | Raw NAPTR record. | no +`ns_rec` \| `ns_record` | Raw NS record. | no +`ptr_rec` \| `ptr_record` | Raw PTR record. | no +`srv_rec` \| `srv_record` | Raw SRV record. | no +`sshfp_rec` \| `sshfp_record` | Raw SSHFP record. | no +`tlsa_rec` \| `tlsa_record` | Raw TLSA record. | no +`txt_rec` \| `txt_record` | Raw TXT record. | no +`uri_rec` \| `uri_record` | Raw URI record. | no +`ip_address` | IP adress for A or AAAA records. Set `record_type` to `A` or `AAAA`. | no +`create_reverse` \| `reverse` | Create reverse records for `A` and `AAAA` record types. There is no equivalent to remove reverse records. (bool) | no +`a_ip_address` | IP adress for A records. Set `record_type` to `A`. | no +`a_create_reverse` | Create reverse records only for `A` records. There is no equivalent to remove reverse records. (bool) | no +`aaaa_ip_address` | IP adress for AAAA records. Set `record_type` `AAAA`. | no +`aaaa_create_reverse` | Create reverse records only for `AAAA` record types. There is no equivalent to remove reverse records. (bool) | no +`a6_data` | A6 record. Set `record_type` to `A6`. | no +`afsdb_subtype` | AFSDB Subtype. Set `record_type` to `AFSDB`. (int) | no +`afsdb_hostname` | AFSDB Hostname. Set `record_type` to `AFSDB`. | no +`cert_type` | CERT Certificate Type. Set `record_type` to `CERT`. (int) | no +`cert_key_tag` | CERT Key Tag. Set `record_type` to `CERT`. (int) | no +`cert_algorithm` | CERT Algorithm. Set `record_type` to `CERT`. (int) | no +`cert_certificate_or_crl` | CERT Certificate or Certificate Revocation List (CRL). Set `record_type` to `CERT`. | no +`cname_hostname` | A hostname which this alias hostname points to. Set `record_type` to `CNAME`. | no +`dlv_key_tag` | DS Key Tag. Set `record_type` to `DLV`. (int) | no +`dlv_algorithm` | DLV Algorithm. Set `record_type` to `DLV`. (int) | no +`dlv_digest_type` | DLV Digest Type. Set `record_type` to `DLV`. (int) | no +`dlv_digest` | DLV Digest. Set `record_type` to `DLV`. | no +`dname_target` | DNAME Target. Set `record_type` to `DNAME`. | no +`ds_key_tag` | DS Key Tag. Set `record_type` to `DS`. (int) | no +`ds_algorithm` | DS Algorithm. Set `record_type` to `DS`. (int) | no +`ds_digest_type` | DS Digest Type. Set `record_type` to `DS`. (int) | no +`ds_digest` | DS Digest. Set `record_type` to `DS`. | no +`kx_preference` | Preference given to this exchanger. Lower values are more preferred. Set `record_type` to `KX`. (int) | no +`kx_exchanger` | A host willing to act as a key exchanger. Set `record_type` to `KX`. | no +`loc_lat_deg` | LOC Degrees Latitude. Set `record_type` to `LOC`. (int) | no +`loc_lat_min` | LOC Minutes Latitude. Set `record_type` to `LOC`. (int) | no +`loc_lat_sec` | LOC Seconds Latitude. Set `record_type` to `LOC`. (float) | no +`loc_lat_dir` | LOC Direction Latitude. Valid values are `N` or `S`. Set `record_type` to `LOC`. (int) | no +`loc_lon_deg` | LOC Degrees Longitude. Set `record_type` to `LOC`. (int) | no +`loc_lon_min` | LOC Minutes Longitude. Set `record_type` to `LOC`. (int) | no +`loc_lon_sec` | LOC Seconds Longitude. Set `record_type` to `LOC`. (float) | no +`loc_lon_dir` | LOC Direction Longitude. Valid values are `E` or `W`. Set `record_type` to `LOC`. (int) | no +`loc_altitude` | LOC Altitude. Set `record_type` to `LOC`. (float) | no +`loc_size` | LOC Size. Set `record_type` to `LOC`. (float) | no +`loc_h_precision` | LOC Horizontal Precision. Set `record_type` to `LOC`. (float) | no +`loc_v_precision` | LOC Vertical Precision. Set `record_type` to `LOC`. (float) | no +`mx_preference` | Preference given to this exchanger. Lower values are more preferred. Set `record_type` to `MX`. (int) | no +`mx_exchanger` | A host willing to act as a mail exchanger. Set `record_type` to `LOC`. | no +`naptr_order` | NAPTR Order. Set `record_type` to `NAPTR`. (int) | no +`naptr_preference` | NAPTR Preference. Set `record_type` to `NAPTR`. (int) | no +`naptr_flags` | NAPTR Flags. Set `record_type` to `NAPTR`. | no +`naptr_service` | NAPTR Service. Set `record_type` to `NAPTR`. | no +`naptr_regexp` | NAPTR Regular Expression. Set `record_type` to `NAPTR`. | no +`naptr_replacement` | NAPTR Replacement. Set `record_type` to `NAPTR`. | no +`ns_hostname` | NS Hostname. Set `record_type` to `NS`. | no +`ptr_hostname` | The hostname this reverse record points to. . Set `record_type` to `PTR`. | no +`srv_priority` | Lower number means higher priority. Clients will attempt to contact the server with the lowest-numbered priority they can reach. Set `record_type` to `SRV`. (int) | no +`srv_weight` | Relative weight for entries with the same priority. Set `record_type` to `SRV`. (int) | no +`srv_port` | SRV Port. Set `record_type` to `SRV`. (int) | no +`srv_target` | The domain name of the target host or '.' if the service is decidedly not available at this domain. Set `record_type` to `SRV`. | no +`sshfp_algorithm` | SSHFP Algorithm. Set `record_type` to `SSHFP`. (int) | no +`sshfp_fp_type` | SSHFP Fingerprint Type. Set `record_type` to `SSHFP`. (int) | no +`sshfp_fingerprint`| SSHFP Fingerprint. Set `record_type` to `SSHFP`. (int) | no +`txt_data` | TXT Text Data. Set `record_type` to `TXT`. | no +`tlsa_cert_usage` | TLSA Certificate Usage. Set `record_type` to `TLSA`. (int) | no +`tlsa_selector` | TLSA Selector. Set `record_type` to `TLSA`. (int) | no +`tlsa_matching_type` | TLSA Matching Type. Set `record_type` to `TLSA`. (int) | no +`tlsa_cert_association_data` | TLSA Certificate Association Data. Set `record_type` to `TLSA`. | no +`uri_target` | Target Uniform Resource Identifier according to RFC 3986. Set `record_type` to `URI`. | no +`uri_priority` | Lower number means higher priority. Clients will attempt to contact the URI with the lowest-numbered priority they can reach. Set `record_type` to `URI`. (int) | no +`uri_weight` | Relative weight for entries with the same priority. Set `record_type` to `URI`. (int) | no + + +Authors +======= + +Rafael Guterres Jeffman diff --git a/README.md b/README.md index c6583fd4190fcd1e273aa2e263ac3b9250c80a9f..246a8b4c01a4132a57d3814f08f2802c5c73ea5a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Features * One-time-password (OTP) support for client installation * Repair mode for clients * Modules for dns forwarder management +* Modules for dns record management * Modules for dns zone management * Modules for group management * Modules for hbacrule management @@ -411,6 +412,7 @@ Modules in plugin/modules * [ipadnsconfig](README-dnsconfig.md) * [ipadnsforwardzone](README-dnsforwardzone.md) +* [ipadnsrecord](README-dnsrecord.md) * [ipadnszone](README-dnszone.md) * [ipagroup](README-group.md) * [ipahbacrule](README-hbacrule.md) diff --git a/playbooks/dnsrecord/ensure-A-and-AAAA-records-are-absent.yml b/playbooks/dnsrecord/ensure-A-and-AAAA-records-are-absent.yml new file mode 100644 index 0000000000000000000000000000000000000000..f4dffc66db52d12829279970fe608e4484712bbb --- /dev/null +++ b/playbooks/dnsrecord/ensure-A-and-AAAA-records-are-absent.yml @@ -0,0 +1,18 @@ +--- +- name: Test PTR Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a PTR record is present + - name: Ensure that 'host04' has A and AAAA records. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: ipatest.local + records: + - name: host04 + a_ip_address: 192.168.122.104 + - name: host04 + aaaa_ip_address: ::1 + state: absent diff --git a/playbooks/dnsrecord/ensure-A-and-AAAA-records-are-present.yml b/playbooks/dnsrecord/ensure-A-and-AAAA-records-are-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..b59acfe0fc2cb456b67088c09911774b8befe632 --- /dev/null +++ b/playbooks/dnsrecord/ensure-A-and-AAAA-records-are-present.yml @@ -0,0 +1,17 @@ +--- +- name: Test PTR Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a PTR record is present + - name: Ensure that 'host04' has A and AAAA records. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: ipatest.local + records: + - name: host04 + a_ip_address: 192.168.122.104 + - name: host04 + aaaa_ip_address: ::1 diff --git a/playbooks/dnsrecord/ensure-CNAME-record-is-absent.yml b/playbooks/dnsrecord/ensure-CNAME-record-is-absent.yml new file mode 100644 index 0000000000000000000000000000000000000000..9b02b14728ab7bdd6d6f2b89d6dac16294d2f586 --- /dev/null +++ b/playbooks/dnsrecord/ensure-CNAME-record-is-absent.yml @@ -0,0 +1,13 @@ +--- +- name: Test CNAME Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure that 'host04' has CNAME, with cname_hostname + - ipadnsrecord: + zone_name: example.com + name: host04 + cname_hostname: host04.example.com + state: absent diff --git a/playbooks/dnsrecord/ensure-CNAME-record-is-present.yml b/playbooks/dnsrecord/ensure-CNAME-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..e6e918c35a072261bc97074d281b70386e40808d --- /dev/null +++ b/playbooks/dnsrecord/ensure-CNAME-record-is-present.yml @@ -0,0 +1,12 @@ +--- +- name: Test CNAME Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure that 'host04' has CNAME, with cname_hostname + - ipadnsrecord: + zone_name: example.com + name: host04 + cname_hostname: host04.example.com diff --git a/playbooks/dnsrecord/ensure-MX-record-is-present.yml b/playbooks/dnsrecord/ensure-MX-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..139c168180aa2d2aa7db61d1b0f280b49d4789d4 --- /dev/null +++ b/playbooks/dnsrecord/ensure-MX-record-is-present.yml @@ -0,0 +1,15 @@ +--- +- name: Ensure MX Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure an MX record is absent + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: '@' + record_type: 'MX' + record_value: '1 mailserver.example.com' + zone_name: example.com + state: present diff --git a/playbooks/dnsrecord/ensure-PTR-record-is-present.yml b/playbooks/dnsrecord/ensure-PTR-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..0a59c0d29e80116571b279f839c371635ac4aaeb --- /dev/null +++ b/playbooks/dnsrecord/ensure-PTR-record-is-present.yml @@ -0,0 +1,15 @@ +--- +- name: Test PTR Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a PTR record is present + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: 5 + record_type: 'PTR' + record_value: 'internal.ipa.example.com' + zone_name: 2.168.192.in-addr.arpa + state: present diff --git a/playbooks/dnsrecord/ensure-SRV-record-is-present.yml b/playbooks/dnsrecord/ensure-SRV-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..3c18ff34f909a485217b137d35995f97cb9d68cc --- /dev/null +++ b/playbooks/dnsrecord/ensure-SRV-record-is-present.yml @@ -0,0 +1,15 @@ +--- +- name: Test SRV Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a SRV record is present + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos._udp.example.com + record_type: 'SRV' + record_value: '10 50 88 ipa.example.com' + zone_name: example.com + state: present diff --git a/playbooks/dnsrecord/ensure-SSHFP-record-is-present.yml b/playbooks/dnsrecord/ensure-SSHFP-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..99ec554251a75448fe8cceb311ca118d640395c1 --- /dev/null +++ b/playbooks/dnsrecord/ensure-SSHFP-record-is-present.yml @@ -0,0 +1,16 @@ +--- +- name: Test SSHFP Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a SSHFP record is present + # SSHFP fingerprint generated with `ssh-keygen -r host04.testzone.local` + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host04 + sshfp_algorithm: 1 + sshfp_fp_type: 1 + sshfp_fingerprint: d21802c61733e055b8d16296cbce300efb8a167a diff --git a/playbooks/dnsrecord/ensure-TLSA-record-is-present.yml b/playbooks/dnsrecord/ensure-TLSA-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..65e947929e35c9dd3ff4e1caa73fe7105dc30b60 --- /dev/null +++ b/playbooks/dnsrecord/ensure-TLSA-record-is-present.yml @@ -0,0 +1,16 @@ +--- +- name: Test SSHFP Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a SSHFP record is present + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: example.com + name: host04 + tlsa_cert_usage: 3 + tlsa_selector: 1 + tlsa_matching_type: 1 + tlsa_cert_association_data: 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 diff --git a/playbooks/dnsrecord/ensure-TXT-record-is-present.yml b/playbooks/dnsrecord/ensure-TXT-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..35be86e164d80f36bc85dcab5b0e0c729cdf6ef3 --- /dev/null +++ b/playbooks/dnsrecord/ensure-TXT-record-is-present.yml @@ -0,0 +1,15 @@ +--- +- name: Test TXT Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a TXT record is absent + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos + record_type: 'TXT' + record_value: 'EXAMPLE.COM' + zone_name: example.com + state: present diff --git a/playbooks/dnsrecord/ensure-URI-record-is-present.yml b/playbooks/dnsrecord/ensure-URI-record-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..be1b25df4d0e609ba3dfc72a2631ba4c2e3160fe --- /dev/null +++ b/playbooks/dnsrecord/ensure-URI-record-is-present.yml @@ -0,0 +1,17 @@ +--- +- name: Test URI Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure a URI record is absent + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _ftp._tcp + record_type: 'URI' + uri_priority: 10 + uri_weight: 1 + uri_target: ftp://ftp.example.com/public + zone_name: example.com + state: present diff --git a/playbooks/dnsrecord/ensure-dnsrecord-is-absent.yml b/playbooks/dnsrecord/ensure-dnsrecord-is-absent.yml new file mode 100644 index 0000000000000000000000000000000000000000..3cfed05c966c0720fe69c8ae84ca0229bdb5b524 --- /dev/null +++ b/playbooks/dnsrecord/ensure-dnsrecord-is-absent.yml @@ -0,0 +1,15 @@ +--- +- name: Test DNS Record is absent. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure that dns record is absent + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' + state: absent diff --git a/playbooks/dnsrecord/ensure-dnsrecord-is-present.yml b/playbooks/dnsrecord/ensure-dnsrecord-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..b1ae113dca4241d025e7dad1c732cadc32e11290 --- /dev/null +++ b/playbooks/dnsrecord/ensure-dnsrecord-is-present.yml @@ -0,0 +1,15 @@ +--- +- name: Test DNS Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure that dns record is present + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' + state: present diff --git a/playbooks/dnsrecord/ensure-dnsrecord-with-reverse-is-present.yml b/playbooks/dnsrecord/ensure-dnsrecord-with-reverse-is-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..bef7d33aafceb7c01dbfb2c9e241407d83e0c2ff --- /dev/null +++ b/playbooks/dnsrecord/ensure-dnsrecord-with-reverse-is-present.yml @@ -0,0 +1,15 @@ +--- +- name: Test DNS Record is present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure that dns record is present + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + ip_address: 192.160.123.45 + create_reverse: yes + state: present diff --git a/playbooks/dnsrecord/ensure-multiple-A-records-are-present.yml b/playbooks/dnsrecord/ensure-multiple-A-records-are-present.yml new file mode 100644 index 0000000000000000000000000000000000000000..eb7be24cec92c1736d31fb1deaef9e8bdc186d95 --- /dev/null +++ b/playbooks/dnsrecord/ensure-multiple-A-records-are-present.yml @@ -0,0 +1,17 @@ +--- +- name: Playbook to manage DNS records. + hosts: ipaserver + become: yes + gather_facts: no + + tasks: + - name: Ensure that 'host04' has multiple A records. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: ipatest.local + name: host01 + a_rec: + - 192.168.122.221 + - 192.168.122.222 + - 192.168.122.223 + - 192.168.122.224 diff --git a/playbooks/dnsrecord/ensure-presence-multiple-records.yml b/playbooks/dnsrecord/ensure-presence-multiple-records.yml new file mode 100644 index 0000000000000000000000000000000000000000..94e01aea7680bb691edc7e2f37b6c2dfcc7e4820 --- /dev/null +++ b/playbooks/dnsrecord/ensure-presence-multiple-records.yml @@ -0,0 +1,21 @@ +--- +- name: Test multiple DNS Records are present. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + # Ensure that multiple dns records are present + - ipadnsrecord: + ipaadmin_password: SomeADMINpassword + records: + - name: host01 + zone_name: example.com + record_type: A + record_value: + - 192.168.122.112 + - 192.168.122.122 + - name: host01 + zone_name: testzone.local + record_type: AAAA + record_value: ::1 diff --git a/plugins/modules/ipadnsrecord.py b/plugins/modules/ipadnsrecord.py new file mode 100644 index 0000000000000000000000000000000000000000..89528e5f7e26a3ca80dbf4066a0fdbc9d7e457dc --- /dev/null +++ b/plugins/modules/ipadnsrecord.py @@ -0,0 +1,1509 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Rafael Guterres Jeffman <rjeffman@redhat.com> +# +# Copyright (C) 2020 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program 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. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +"""DNS Record ansible-freeipa module.""" + +ANSIBLE_METADATA = { + "metadata_version": "1.0", + "supported_by": "community", + "status": ["preview"], +} + +DOCUMENTATION = """ +--- +module: ipadnsrecord +short description: Manage FreeIPA DNS records +description: Manage FreeIPA DNS records +options: + ipaadmin_principal: + description: The admin principal + default: admin + ipaadmin_password: + description: The admin password + required: false + records: + description: The list of user dns records dicts + required: false + options: + name: + description: The DNS record name to manage. + aliases: ["record_name"] + required: true + zone_name: + description: The DNS zone name to which DNS record needs to be managed. + aliases: ["dnszone"] + required: true (if not provided globally) + record_type: + description: The type of DNS record. + choices: ["A", "AAAA", "A6", "AFSDB", "CERT", "CNAME", "DLV", "DNAME", + "DS", "KX", "LOC", "MX", "NAPTR", "NS", "PTR", "SRV", + "SSHFP", "TLSA", "TXT", "URI"] + default: "A" + record_value: + description: Manage DNS record name with these values. + required: false + type: list + record_ttl: + description: Set the TTL for the record. + required: false + type: int + del_all: + description: Delete all associated records. + required: false + type: bool + a_rec: + description: Raw A record. + required: false + aliases: ["a_record"] + aaaa_rec: + description: Raw AAAA record. + required: false + aliases: ["aaaa_record"] + a6_rec: + description: Raw A6 record. + required: false + aliases: ["a6_record"] + afsdb_rec: + description: Raw AFSDB record. + required: false + aliases: ["afsdb_record"] + cert_rec: + description: Raw CERT record. + required: false + aliases: ["cert_record"] + cname_rec: + description: Raw CNAME record. + required: false + aliases: ["cname_record"] + dlv_rec: + description: Raw DLV record. + required: false + aliases: ["dlv_record"] + dname_rec: + description: Raw DNAM record. + required: false + aliases: ["dname_record"] + ds_rec: + description: Raw DS record. + required: false + aliases: ["ds_record"] + kx_rec: + description: Raw KX record. + required: false + aliases: ["kx_record"] + loc_rec: + description: Raw LOC record. + required: false + aliases: ["loc_record"] + mx_rec: + description: Raw MX record. + required: false + aliases: ["mx_record"] + naptr_rec: + description: Raw NAPTR record. + required: false + aliases: ["naptr_record"] + ns_rec: + description: Raw NS record. + required: false + aliases: ["ns_record"] + ptr_rec: + description: Raw PTR record. + required: false + aliases: ["ptr_record"] + srv_rec: + description: Raw SRV record. + required: false + aliases: ["srv_record"] + sshfp_rec: + description: Raw SSHFP record. + required: false + aliases: ["sshfp_record"] + tlsa_rec: + description: Raw TLSA record. + required: false + aliases: ["tlsa_record"] + txt_rec: + description: Raw TXT record. + required: false + aliases: ["txt_record"] + uri_rec: + description: Raw URI record. + required: false + aliases: ["uri_record"] + ip_address: + description: IP adresses for A or AAAA records. + required: false + type: string + a_ip_address: + description: IP adresses for A records. + required: false + type: string + a_create_reverse: + description: + Create reverse record for A records. + There is no equivalent to remove reverse records. + type: bool + required: false + aaaa_ip_address: + description: IP adresses for AAAA records. + required: false + type: string + aaaa_create_reverse: + description: + Create reverse record for AAAA records. + There is no equivalent to remove reverse records. + type: bool + required: false + create_reverse: + description: + Create reverse record for A or AAAA record types. + There is no equivalent to remove reverse records. + type: bool + required: false + aliases: ["reverse"] + a6_data: + description: A6 record data. + required: false + afsdb_subtype: + description: AFSDB Subtype + required: false + type: int + afsdb_hostname: + discription: AFSDB Hostname + required: false + type: string + cert_type: + descriptioon: CERT Certificate Type + required: false + type: int + cert_key_tag: + description: CERT Key Tag + required: false + type: int + cert_algorithm: + description: CERT Algorithm + required: false + type: int + cert_certificate_or_crl: + description: CERT Certificate or Certificate Revocation List (CRL). + required: false + type: string + cname_hostname: + description: A hostname which this alias hostname points to. + required: false + type: string + dlv_key_tag: + description: DS Key Tag + required: false + type: int + dlv_algorithm: + description: DLV Algorithm + required: false + type: int + dlv_digest_type: + description: DLV Digest Type + required: false + type: int + dlv_digest: + descriptinion: DLV Digest + required: false + type: string + dname_target: + description: DNAME Target + required: false + type: string + ds_key_tag: + description: DS Key Tag + required: false + type: int + ds_algorithm: + description: DS Algorithm + required: false + type: int + ds_digest_type: + description: DS Digest Type + required: false + type: int + ds_digest: + descriptinion: DS Digest + required: false + type: string + kx_preference: + description: + Preference given to this exchanger. Lower values are more preferred. + required: false + type: int + kx_exchanger: + description: A host willing to act as a key exchanger. + required: false + type: string + loc_lat_deg: + description: LOC Degrees Latitude + required: false + type: int + loc_lat_min: + description: LOC Minutes Latitude + required: false + type: int + loc_lat_sec: + description: LOC Seconds Latitude + required: false + type: float + loc_lat_dir: + description: LOC Direction Latitude + required: false + choices: ["N", "S"] + loc_lon_deg: + description: LOC Degrees Longitude + required: false + type: int + loc_lon_min: + description: LOC Minutes Longitude + required: false + type: int + loc_lon_sec: + description: LOC Seconds Longitude + required: false + type: float + loc_lon_dir: + description: LOC Direction Longitude + required: false + choices: ["E", "W"] + loc_altitude: + description: LOC Altitude + required: false + type: float + loc_size: + description: LOC Size + required: false + type: float + loc_h_precision: + description: LOC Horizontal Precision + required: false + type: float + loc_v_precision: + description: LOC Vertical Precision + required: false + type: float + mx_preference: + description: + Preference given to this exchanger. Lower values are more preferred. + required: false + type: int + mx_exchanger: + description: A host willing to act as a mail exchanger. + required: false + type: string + naptr_order: + description: NAPTR Order + required: false + type: int + naptr_preference: + description: NAPTR Preference + required: false + type: int + naptr_flags: + description: NAPTR Flags + required: false + type: string + naptr_service: + description: NAPTR Service + required: false + type: string + naptr_regexp: + description: NAPTR Regular Expression + required: false + type: string + naptr_replacement: + description: NAPTR Replacement + required: false + type: string + ns_hostname: + description: NS Hostname + required: false + type: string + ptr_hostname: + description: The hostname this reverse record points to. + required: false + type: string + srv_priority: + description: + Lower number means higher priority. Clients will attempt to contact + the server with the lowest-numbered priority they can reach. + required: false + type: int + srv_weight: + description: Relative weight for entries with the same priority. + required: false + type: int + srv_port: + description: SRV Port + required: false + type: int + srv_target: + description: + The domain name of the target host or '.' if the service is decidedly + not available at this domain. + required: false + type: string + sshfp_algorithm: + description: SSHFP Algorithm + sshfp_fp_type: + description: SSHFP Fingerprint Type + required: False + type: int + sshfp_fingerprint: + description: SSHFP Fingerprint + required: False + type: string + txt_data: + description: TXT Text Data + required: false + type: string + tlsa_cert_usage: + description: TLSA Certificate Usage + required: false + type: int + tlsa_selector: + descrpition: TLSA Selector + required: false + type: int + tlsa_matching_type: + descrpition: TLSA Matching Type + required: false + type: int + tlsa_cert_association_data: + descrpition: TLSA Certificate Association Data + required: false + type: string + uri_target: + description: Target Uniform Resource Identifier according to RFC 3986. + required: false + type: string + uri_priority: + description: + Lower number means higher priority. Clients will attempt to contact + the URI with the lowest-numbered priority they can reach. + required: false + type: int + uri_weight: + description: Relative weight for entries with the same priority. + required: false + type: int + zone_name: + description: The DNS zone name to which DNS record needs to be managed. + aliases: ["dnszone"] + required: true (if not provided on each record) + name: + description: The DNS record name to manage. + aliases: ["record_name"] + required: true + record_type: + description: The type of DNS record. + required: false + choices: ["A", "AAAA", "A6", "AFSDB", "CERT", "CNAME", "DLV", "DNAME", + "DS", "KX", "LOC", "MX", "NAPTR", "NS", "PTR", "SRV", "SSHFP", + "TLSA", "TXT", "URI"] + default: "A" + record_value: + description: Manage DNS record name with this values. + required: false + type: list + record_ttl: + description: Set the TTL for the record. + required: false + type: int + del_all: + description: Delete all associated records. + required: false + type: bool + a_rec: + description: Raw A record. + required: false + aliases: ["a_record"] + aaaa_rec: + description: Raw AAAA record. + required: false + aliases: ["aaaa_record"] + a6_rec: + description: Raw A6 record. + required: false + aliases: ["a6_record"] + afsdb_rec: + description: Raw AFSDB record. + required: false + aliases: ["afsdb_record"] + cert_rec: + description: Raw CERT record. + required: false + aliases: ["cert_record"] + cname_rec: + description: Raw CNAME record. + required: false + aliases: ["cname_record"] + dlv_rec: + description: Raw DLV record. + required: false + aliases: ["dlv_record"] + dname_rec: + description: Raw DNAM record. + required: false + aliases: ["dname_record"] + ds_rec: + description: Raw DS record. + required: false + aliases: ["ds_record"] + kx_rec: + description: Raw KX record. + required: false + aliases: ["kx_record"] + loc_rec: + description: Raw LOC record. + required: false + aliases: ["loc_record"] + mx_rec: + description: Raw MX record. + required: false + aliases: ["mx_record"] + naptr_rec: + description: Raw NAPTR record. + required: false + aliases: ["naptr_record"] + ns_rec: + description: Raw NS record. + required: false + aliases: ["ns_record"] + ptr_rec: + description: Raw PTR record. + required: false + aliases: ["ptr_record"] + srv_rec: + description: Raw SRV record. + required: false + aliases: ["srv_record"] + sshfp_rec: + description: Raw SSHFP record. + required: false + aliases: ["sshfp_record"] + tlsa_rec: + description: Raw TLSA record. + required: false + aliases: ["tlsa_record"] + txt_rec: + description: Raw TXT record. + required: false + aliases: ["txt_record"] + uri_rec: + description: Raw URI record. + required: false + aliases: ["uri_record"] + ip_address: + description: IP adresses for A ar AAAA. + aliases: ["a_ip_address", "aaaa_ip_address"] + required: false + type: string + create_reverse: + description: + Create reverse record for A or AAAA record types. + There is no equivalent to remove reverse records. + type: bool + required: false + aliases: ["reverse"] + a_ip_address: + description: IP adresses for A records. + required: false + type: string + a_create_reverse: + description: + Create reverse record for A records. + There is no equivalent to remove reverse records. + type: bool + required: false + aaaa_ip_address: + description: IP adresses for AAAA records. + required: false + type: string + aaaa_create_reverse: + description: + Create reverse record for AAAA records. + There is no equivalent to remove reverse records. + type: bool + required: false + afsdb_subtype: + description: AFSDB Subtype + required: false + type: int + afsdb_hostname: + discription: AFSDB Hostname + required: false + type: string + cert_type: + descriptioon: CERT Certificate Type + required: false + type: int + cert_key_tag: + description: CERT Key Tag + required: false + type: int + cert_algorithm: + description: CERT Algorithm + required: false + type: int + cert_certificate_or_crl: + description: CERT Certificate/CRL + required: false + type: string + cname_hostname: + description: A hostname which this alias hostname points to. + required: false + type: string + dlv_key_tag: + description: DS Key Tag + required: false + type: int + dlv_algorithm: + description: DLV Algorithm + required: false + type: int + dlv_digest_type: + description: DLV Digest Type + required: false + type: int + dlv_digest: + descriptinion: DLV Digest + required: false + type: string + dname_target: + description: DNAME Target + required: false + type: string + ds_key_tag: + description: DS Key Tag + required: false + type: int + ds_algorithm: + description: DS Algorithm + required: false + type: int + ds_digest_type: + description: DS Digest Type + required: false + type: int + ds_digest: + descriptinion: DS Digest + required: false + type: string + kx_preference: + description: + Preference given to this exchanger. Lower values are more preferred. + required: false + type: int + kx_exchanger: + description: A host willing to act as a key exchanger. + required: false + type: string + loc_lat_deg: + description: LOC Degrees Latitude + required: false + type: int + loc_lat_min: + description: LOC Minutes Latitude + required: false + type: int + loc_lat_sec: + description: LOC Seconds Latitude + required: false + type: float + loc_lat_dir: + description: LOC Direction Latitude + required: false + choices: ["N", "S"] + loc_lon_deg: + description: LOC Degrees Longitude + required: false + type: int + loc_lon_min: + description: LOC Minutes Longitude + required: false + type: int + loc_lon_sec: + description: LOC Seconds Longitude + required: false + type: float + loc_lon_dir: + description: LOC Direction Longitude + required: false + choices: ["E", "W"] + loc_altitude: + description: LOC Altitude + required: false + type: float + loc_size: + description: LOC Size + required: false + type: float + loc_h_precision: + description: LOC Horizontal Precision + required: false + type: float + loc_v_precision: + description: LOC Vertical Precision + required: false + type: float + mx_preference: + description: + Preference given to this exchanger. Lower values are more preferred. + required: false + type: int + mx_exchanger: + description: A host willing to act as a mail exchanger. + required: false + type: string + naptr_order: + description: NAPTR Order + required: false + type: int + naptr_preference: + description: NAPTR Preference + required: false + type: int + naptr_flags: + description: NAPTR Flags + required: false + type: string + naptr_service: + description: NAPTR Service + required: false + type: string + naptr_regexp: + description: NAPTR Regular Expression + required: false + type: string + naptr_replacement: + description: NAPTR Replacement + required: false + type: string + ns_hostname: + description: NS Hostname + required: false + type: string + ptr_hostname: + description: The hostname this reverse record points to. + required: false + type: string + srv_priority: + description: + Lower number means higher priority. Clients will attempt to contact the + server with the lowest-numbered priority they can reach. + required: false + type: int + srv_weight: + description: Relative weight for entries with the same priority. + required: false + type: int + srv_port: + description: SRV Port + required: false + type: int + srv_target: + description: + The domain name of the target host or '.' if the service is decidedly not + available at this domain. + required: false + type: string + sshfp_algorithm: + description: SSHFP Algorithm + sshfp_fp_type: + description: SSHFP Fingerprint Type + required: False + type: int + sshfp_fingerprint: + description: SSHFP Fingerprint + required: False + type: string + txt_data: + description: TXT Text Data + required: false + type: string + tlsa_cert_usage: + description: TLSA Certificate Usage + required: false + type: int + tlsa_selector: + descrpition: TLSA Selector + required: false + type: int + tlsa_matching_type: + descrpition: TLSA Matching Type + required: false + type: int + tlsa_cert_association_data: + descrpition: TLSA Certificate Association Data + required: false + type: string + uri_target: + description: Target Uniform Resource Identifier according to RFC 3986. + required: false + type: string + uri_priority: + description: + Lower number means higher priority. Clients will attempt to contact the + URI with the lowest-numbered priority they can reach. + required: false + type: int + uri_weight: + description: Relative weight for entries with the same priority. + required: false + type: int + state: + description: State to ensure + default: present + choices: ["present", "absent"] + +author: + - Rafael Guterres Jeffman +""" + +EXAMPLES = """ +# Ensure dns record is present +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: vm-001 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' + +# Ensure that dns record exists with a TTL +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' + record_ttl: 300 + +# Ensure that dns record exists with a reverse record +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host02 + zone_name: example.com + record_type: 'AAAA' + record_value: 'fd00::0002' + create_reverse: yes + +# Ensure a PTR record is present +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: 5 + zone_name: 2.168.192.in-addr.arpa + record_type: 'PTR' + record_value: 'internal.ipa.example.com' + +# Ensure a TXT record is present +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos + zone_name: example.com + record_type: 'TXT' + record_value: 'EXAMPLE.COM' + +# Ensure a SRV record is present +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos._udp.example.com + zone_name: example.com + record_type: 'SRV' + record_value: '10 50 88 ipa.example.com' + +# Ensure an MX record is present +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: '@' + zone_name: example.com + record_type: 'MX' + record_value: '1 mailserver.example.com' + +# Ensure that dns record is absent +- ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: example.com + record_type: 'AAAA' + record_value: '::1' + state: absent +""" + +RETURN = """ +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_text +from ansible.module_utils.ansible_freeipa_module import temp_kinit, \ + temp_kdestroy, valid_creds, api_connect, api_command, module_params_get, \ + is_ipv4_addr, is_ipv6_addr +import dns.reversename +import dns.resolver +import ipalib.errors +import six + + +if six.PY3: + unicode = str + +_SUPPORTED_RECORD_TYPES = [ + "A", "AAAA", "A6", "AFSDB", "CERT", "CNAME", "DLV", "DNAME", "DS", "KX", + "LOC", "MX", "NAPTR", "NS", "PTR", "SRV", "SSHFP", "TLSA", "TXT", "URI"] + +_RECORD_FIELDS = [ + "a_rec", "aaaa_rec", "a6_rec", "afsdb_rec", "cert_rec", + "cname_rec", "dlv_rec", "dname_rec", "ds_rec", "kx_rec", "loc_rec", + "mx_rec", "naptr_rec", "ns_rec", "ptr_rec", "srv_rec", "sshfp_rec", + "tlsa_rec", "txt_rec", "uri_rec" +] + +_PART_MAP = { + 'a_ip_address': 'a_part_ip_address', + 'a_create_reverse': 'a_extra_create_reverse', + 'aaaa_ip_address': 'aaaa_part_ip_address', + 'aaaa_create_reverse': 'aaaa_extra_create_reverse', + 'a6_data': 'a6_part_data', + 'afsdb_subtype': 'afsdb_part_subtype', + 'afsdb_hostname': 'afsdb_part_hostname', + 'cert_type': 'cert_part_type', + 'cert_key_tag': 'cert_part_key_tag', + 'cert_algorithm': 'cert_part_algorithm', + 'cert_certificate_or_crl': 'cert_part_certificate_or_crl', + 'cname_hostname': 'cname_part_hostname', + 'dlv_algorithm': 'dlv_part_algorithm', + 'dlv_digest': 'dlv_part_digest', + 'dlv_digest_type': 'dlv_part_digest_type', + 'dlv_key_tag': 'dlv_part_key_tag', + 'dname_target': 'dname_part_target', + 'ds_algorithm': 'ds_part_algorithm', + 'ds_digest': 'ds_part_digest', + 'ds_digest_type': 'ds_part_digest_type', + 'ds_key_tag': 'ds_part_key_tag', + 'kx_preference': 'kx_part_preference', + 'kx_exchanger': 'kx_part_exchanger', + "loc_lat_deg": "loc_part_lat_deg", + "loc_lat_min": "loc_part_lat_min", + "loc_lat_sec": "loc_part_lat_sec", + "loc_lat_dir": "loc_part_lat_dir", + "loc_lon_deg": "loc_part_lon_deg", + "loc_lon_min": "loc_part_lon_min", + "loc_lon_sec": "loc_part_lon_sec", + "loc_lon_dir": "loc_part_lon_dir", + "loc_altitude": "loc_part_altitude", + "loc_size": "loc_part_size", + "loc_h_precision": "loc_part_h_precision", + "loc_v_precision": "loc_part_v_precision", + "mx_preference": "mx_part_preference", + "mx_exchanger": 'mx_part_exchanger', + "naptr_order": "naptr_part_order", + "naptr_preference": "naptr_part_preference", + "naptr_flags": "naptr_part_flags", + "naptr_service": "naptr_part_service", + "naptr_regexp": "naptr_part_regexp", + "naptr_replacement": "naptr_part_replacement", + 'ns_hostname': 'ns_part_hostname', + 'ptr_hostname': 'ptr_part_hostname', + "srv_priority": "srv_part_priority", + "srv_weight": "srv_part_weight", + "srv_port": "srv_part_port", + "srv_target": "srv_part_target", + 'sshfp_algorithm': 'sshfp_part_algorithm', + 'sshfp_fingerprint': 'sshfp_part_fingerprint', + 'sshfp_fp_type': 'sshfp_part_fp_type', + "tlsa_cert_usage": "tlsa_part_cert_usage", + "tlsa_cert_association_data": "tlsa_part_cert_association_data", + "tlsa_matching_type": "tlsa_part_matching_type", + "tlsa_selector": "tlsa_part_selector", + 'txt_data': 'txt_part_data', + "uri_priority": "uri_part_priority", + "uri_target": "uri_part_target", + "uri_weight": "uri_part_weight" +} + +_RECORD_PARTS = { + "arecord": ["a_part_ip_address", "a_extra_create_reverse"], + "aaaarecord": [ + "aaaa_part_ip_address", "aaaa_extra_create_reverse" + ], + "a6record": ["a6_part_data"], + "afsdbrecord": ['afsdb_part_subtype', 'afsdb_part_hostname'], + "cert_rec": [ + 'cert_part_type', 'cert_part_key_tag', 'cert_part_algorithm', + 'cert_part_certificate_or_crl' + ], + "cnamerecord": ["cname_part_hostname"], + "dlvrecord": [ + 'dlv_part_key_tag', 'dlv_part_algorithm', 'dlv_part_digest_type', + 'dlv_part_digest' + ], + "dnamerecord": ["dname_part_target"], + "dsrecord": ['ds_part_key_tag', 'ds_part_algorithm', + 'ds_part_digest_type', 'ds_part_digest'], + "kxrecord": ['kx_part_preference', 'kx_part_exchanger'], + "locrecord": [ + "loc_part_lat_deg", "loc_part_lat_min", "loc_part_lat_sec", + "loc_part_lat_dir", "loc_part_lon_deg", "loc_part_lon_min", + "loc_part_lon_sec", "loc_part_lon_dir", "loc_part_altitude", + "loc_part_size", "loc_part_h_precision", "loc_part_v_precision" + ], + "mxrecord": ['mx_part_preference', 'mx_part_exchanger'], + "naptrrecord": [ + "naptr_part_order", "naptr_part_preference", "naptr_part_flags", + "naptr_part_service", "naptr_part_regexp", "naptr_part_replacement" + ], + "nsrecord": ["ns_part_hostname"], + "ptrrecord": ["ptr_part_hostname"], + "srvrecord": [ + "srv_part_priority", "srv_part_weight", "srv_part_port", + "srv_part_target", + ], + "sshfprecord": [ + 'sshfp_part_algorithm', 'sshfp_part_fingerprint', + 'sshfp_part_fp_type' + ], + "tlsarecord": [ + "tlsa_part_cert_usage", "tlsa_part_cert_association_data", + "tlsa_part_matching_type", "tlsa_part_selector" + ], + "txtrecord": ["txt_part_data"], + "urirecord": ["uri_part_priority", "uri_part_target", "uri_part_weight"], +} + + +def configure_module(): + """Configure ipadnsrecord ansible module variables.""" + record_spec = dict( + zone_name=dict(type='str', required=False, aliases=['dnszone']), + record_type=dict(type='str', default="A", + choices=["A", "AAAA", "A6", "AFSDB", "CERT", "CNAME", + "DLV", "DNAME", "DS", "KX", "LOC", "MX", + "NAPTR", "NS", "PTR", "SRV", "SSHFP", "TLSA", + "TXT", "URI"]), + record_value=dict(type='list', required=False), + record_ttl=dict(type='int', required=False), + del_all=dict(type='bool', required=False), + a_rec=dict(type='list', required=False, aliases=['a_record']), + aaaa_rec=dict(type='list', required=False, aliases=['aaaa_record']), + a6_rec=dict(type='list', required=False, aliases=['a6_record']), + afsdb_rec=dict(type='list', required=False, aliases=['afsdb_record']), + cert_rec=dict(type='list', required=False, aliases=['cert_record']), + cname_rec=dict(type='list', required=False, aliases=['cname_record']), + dlv_rec=dict(type='list', required=False, aliases=['dlv_record']), + dname_rec=dict(type='list', required=False, aliases=['dname_record']), + ds_rec=dict(type='list', required=False, aliases=['ds_record']), + kx_rec=dict(type='list', required=False, aliases=['kx_record']), + loc_rec=dict(type='list', required=False, aliases=['loc_record']), + mx_rec=dict(type='list', required=False, aliases=['mx_record']), + naptr_rec=dict(type='list', required=False, aliases=['naptr_record']), + ns_rec=dict(type='list', required=False, aliases=['ns_record']), + ptr_rec=dict(type='list', required=False, aliases=['ptr_record']), + srv_rec=dict(type='list', required=False, aliases=['srv_record']), + sshfp_rec=dict(type='list', required=False, aliases=['sshfp_record']), + tlsa_rec=dict(type='list', required=False, aliases=['tlsa_record']), + txt_rec=dict(type='list', required=False, aliases=['txt_record']), + uri_rec=dict(type='list', required=False, aliases=['uri_record']), + ip_address=dict(type='str', required=False), + create_reverse=dict(type='bool', required=False, aliases=['reverse']), + a_ip_address=dict(type='str', required=False), + a_create_reverse=dict(type='bool', required=False), + aaaa_ip_address=dict(type='str', required=False), + aaaa_create_reverse=dict(type='bool', required=False), + a6_data=dict(type='str', required=False), + afsdb_subtype=dict(type='int', required=False), + afsdb_hostname=dict(type='str', required=False), + cert_type=dict(type='int', required=False), + cert_key_tag=dict(type='int', required=False), + cert_algorithm=dict(type='int', required=False), + cert_certificate_or_crl=dict(type='str', required=False), + cname_hostname=dict(type='str', required=False), + dlv_key_tag=dict(type='int', required=False), + dlv_algorithm=dict(type='int', required=False), + dlv_digest_type=dict(type='int', required=False), + dlv_digest=dict(type='str', required=False), + dname_target=dict(type='str', required=False), + ds_key_tag=dict(type='int', required=False), + ds_algorithm=dict(type='int', required=False), + ds_digest_type=dict(type='int', required=False), + ds_digest=dict(type='str', required=False), + kx_preference=dict(type='int', required=False), + kx_exchanger=dict(type='str', required=False), + loc_lat_deg=dict(type='int', required=False), + loc_lat_min=dict(type='int', required=False), + loc_lat_sec=dict(type='float', required=False), + loc_lat_dir=dict(type='str', required=False), + loc_lon_deg=dict(type='int', required=False), + loc_lon_min=dict(type='int', required=False), + loc_lon_sec=dict(type='float', required=False), + loc_lon_dir=dict(type='str', required=False), + loc_altitude=dict(type='float', required=False), + loc_size=dict(type='float', required=False), + loc_h_precision=dict(type='float', required=False), + loc_v_precision=dict(type='float', required=False), + mx_preference=dict(type='int', required=False), + mx_exchanger=dict(type='str', required=False), + naptr_order=dict(type='int', required=False), + naptr_preference=dict(type='int', required=False), + naptr_flags=dict(type='str', required=False), + naptr_service=dict(type='str', required=False), + naptr_regexp=dict(type='str', required=False), + naptr_replacement=dict(type='str', required=False), + ns_hostname=dict(type='str', required=False), + ptr_hostname=dict(type='str', required=False), + srv_priority=dict(type='int', required=False), + srv_weight=dict(type='int', required=False), + srv_port=dict(type='int', required=False), + srv_target=dict(type='str', required=False), + sshfp_algorithm=dict(type='int', required=False), + sshfp_fingerprint=dict(type='str', required=False), + sshfp_fp_type=dict(type='int', required=False), + tlsa_cert_usage=dict(type='int', required=False), + tlsa_cert_association_data=dict(type='str', required=False), + tlsa_matching_type=dict(type='int', required=False), + tlsa_selector=dict(type='int', required=False), + txt_data=dict(type='str', required=False), + uri_priority=dict(type='int', required=False), + uri_target=dict(type='str', required=False), + uri_weight=dict(type='int', required=False), + ) + + ansible_module = AnsibleModule( + argument_spec=dict( + # general + ipaadmin_principal=dict(type="str", default="admin"), + ipaadmin_password=dict(type="str", no_log=True), + + name=dict(type="list", aliases=["record_name"], default=None, + required=False), + + records=dict(type="list", default=None, + options=dict( + # Here name is a simple string + name=dict(type='str', required=True, + aliases=['record_name']), + **record_spec), + ), + + # general + state=dict(type="str", default="present", + choices=["present", "absent", "disabled"]), + + # Add record specific parameters for simple use case + **record_spec + ), + mutually_exclusive=[["name", "records"], ['record_value', 'del_all']], + required_one_of=[["name", "records"]], + supports_check_mode=True, + ) + + ansible_module._ansible_debug = True + + return ansible_module + + +def find_dnsrecord(module, dnszone, name, **records): + """Find a DNS record based on its name (idnsname).""" + _args = {record: value for record, value in records.items()} + _args["all"] = True + if name != '@': + _args['idnsname'] = to_text(name) + + try: + _result = api_command( + module, "dnsrecord_find", to_text(dnszone), _args) + except ipalib.errors.NotFound: + return None + + if len(_result["result"]) > 1 and name != '@': + module.fail_json( + msg="There is more than one dnsrecord for '%s'," + " zone '%s'" % (name, dnszone)) + else: + if len(_result["result"]) == 1: + return _result["result"][0] + else: + for _res in _result["result"]: + if 'idnsname' in _res: + for x in _res['idnsname']: + if '@' == to_text(x): + return _res + return None + + +def check_parameters(module, state, zone_name, record): + """Check if parameters are correct.""" + if zone_name is None: + module.fail_json(msg="Msssing required argument: zone_name") + + record_type = record.get('record_type', None) + record_value = record.get('record_value', None) + if record_type is not None: + if record_type not in _SUPPORTED_RECORD_TYPES: + module.fail_json( + msg="Record Type '%s' is not supported." % record_type) + + has_record = any(record.get(rec, None) for rec in _RECORD_FIELDS) + + has_part_record = any(record.get(rec, None) for rec in _PART_MAP) + + special_list = ['ip_address'] + has_special = any(record.get(rec, None) for rec in special_list) + + invalid = [] + + if state == 'present': + if has_record or has_part_record or has_special: + if record_value: + module.fail_json( + msg="Cannot use record data with `record_value`.") + elif not record_value: + module.fail_json(msg="No record data provided.") + + invalid = ['del_all'] + + if state == 'absent': + del_all = record.get('del_all', None) + if record_value: + if has_record or has_part_record or del_all: + module.fail_json( + msg="Cannot use record data with `record_value`.") + elif not (has_record or has_part_record or del_all): + module.fail_json( + msg="Either a record description or `del_all` is required.") + invalid = list(_PART_MAP.keys()) + invalid.extend(['create_reverse', 'dns_ttl']) + + for x in invalid: + if x in record: + module.fail_json( + msg="Variable `%s` cannot be used in state `%s`" % + (x, state)) + + +def connect_to_api(module): + """Connect to the IPA API.""" + ipaadmin_principal = module_params_get(module, "ipaadmin_principal") + ipaadmin_password = module_params_get(module, "ipaadmin_password") + + ccache_dir = None + ccache_name = None + if not valid_creds(module, ipaadmin_principal): + ccache_dir, ccache_name = temp_kinit(ipaadmin_principal, + ipaadmin_password) + api_connect() + + return ccache_dir, ccache_name + + +def get_entry_from_module(module, name): + """Create an entry dict from attributes in module.""" + attrs = [ + 'del_all', 'zone_name', 'record_type', 'record_value', 'record_ttl', + "ip_address", "create_reverse" + ] + + entry = {'name': name} + + for key_set in [_RECORD_FIELDS, _PART_MAP, attrs]: + entry.update({ + key: module_params_get(module, key) + for key in key_set + if module_params_get(module, key) is not None + }) + + return entry + + +def create_reverse_ip_record(module, zone_name, name, ips): + """Create a reverse record for an IP (PTR record).""" + _cmds = [] + for address in ips: + reverse_ip = dns.reversename.from_address(address) + reverse_zone = dns.resolver.zone_for_name(reverse_ip) + reverse_host = to_text(reverse_ip).replace(".%s" % reverse_zone, '') + + rev_find = find_dnsrecord(module, reverse_zone, reverse_host) + if rev_find is None: + rev_args = { + 'idnsname': to_text(reverse_host), + "ptrrecord": "%s.%s" % (name, zone_name) + } + _cmds.append([reverse_zone, 'dnsrecord_add', rev_args]) + + return _cmds + + +def ensure_data_is_list(data): + """Ensure data is represented as a list.""" + return data if isinstance(data, list) else [data] + + +def gen_args(entry): + """Generate IPA API arguments for a given `entry`.""" + args = {'idnsname': to_text(entry['name'])} + + if 'del_all' in entry: + args['del_all'] = entry['del_all'] + + record_value = entry.get('record_value', None) + + if record_value is not None: + record_type = entry['record_type'] + rec = "{}record".format(record_type.lower()) + args[rec] = ensure_data_is_list(record_value) + + else: + for field in _RECORD_FIELDS: + record_value = entry.get(field, None) + if record_value is not None: + record_type = field.split('_')[0] + rec = "{}record".format(record_type.lower()) + args[rec] = ensure_data_is_list(record_value) + + records = { + key: rec for key, rec in _PART_MAP.items() if key in entry + } + for key, rec in records.items(): + args[rec] = entry[key] + + if 'ip_address' in entry: + ip_address = entry['ip_address'] + if is_ipv4_addr(ip_address): + args['a_part_ip_address'] = ip_address + if is_ipv6_addr(ip_address): + args['aaaa_part_ip_address'] = ip_address + + if entry.get('create_reverse', False): + if 'a_part_ip_address' in args or 'arecord' in args: + args['a_extra_create_reverse'] = True + if 'aaaa_part_ip_address' in args or 'aaaarecord' in args: + args['aaaa_extra_create_reverse'] = True + + if 'record_ttl' in entry: + args['dnsttl'] = entry['record_ttl'] + + return args + + +def define_commands_for_present_state(module, zone_name, entry, res_find): + """Define commnads for `state: present`.""" + _commands = [] + + name = to_text(entry['name']) + args = gen_args(entry) + + if res_find is None: + _commands.append([zone_name, 'dnsrecord_add', args]) + else: + # Create reverse records for existing records + for ipv in ['a', 'aaaa']: + record = ('%srecord' % ipv) + if record in args and ('%s_extra_create_reverse' % ipv) in args: + cmds = create_reverse_ip_record( + module, zone_name, name, args[record]) + _commands.extend(cmds) + del args['%s_extra_create_reverse' % ipv] + if '%s_ip_address' not in args: + del args[record] + for record, fields in _RECORD_PARTS.items(): + part_fields = [f for f in fields if f in args] + if part_fields: + if record in args: + # user wants to update record. + if len(args[record]) > 1: + module.fail_json(msg="Cannot modify multiple records " + "of the same type at once.") + + existing = find_dnsrecord(module, zone_name, name, + **{record: args[record][0]}) + if existing is None: + module.fail_json(msg="``%s` not found." % record) + else: + # update DNS record + _args = {k: args[k] for k in part_fields if k in args} + _args["idnsname"] = to_text(args["idnsname"]) + _args[record] = res_find[record] + if 'dns_ttl' in args: + _args['dns_ttl'] = args['dns_ttl'] + _commands.append([zone_name, 'dnsrecord_mod', _args]) + # remove record from args, as it will not be used again. + del args[record] + else: + for f in part_fields: + _args = {k: args[k] for k in part_fields} + _args['idnsname'] = name + _commands.append([zone_name, 'dnsrecord_add', _args]) + # clean used fields from args + for f in part_fields: + if f in args: + del args[f] + else: + if record in args: + add_list = [] + for value in args[record]: + existing = find_dnsrecord(module, zone_name, name, + **{record: value}) + if existing is None: + add_list.append(value) + if add_list: + args[record] = add_list + _commands.append([zone_name, 'dnsrecord_add', args]) + + return _commands + + +def define_commands_for_absent_state(module, zone_name, entry, res_find): + """Define commands for `state: absent`.""" + _commands = [] + if res_find is None: + return [] + + name = entry['name'] + args = gen_args(entry) + + del_all = args.get('del_all', False) + + records_to_delete = {k: v for k, v in args.items() if k.endswith('record')} + + if del_all and records_to_delete: + module.fail_json(msg="Cannot use del_all and record together.") + + if not del_all: + delete_records = False + for record, values in records_to_delete.items(): + del_list = [] + for value in values: + existing = find_dnsrecord( + module, zone_name, name, **{record: value}) + if existing: + del_list.append(value) + if del_list: + args[record] = del_list + delete_records = True + if delete_records: + _commands.append([zone_name, 'dnsrecord_del', args]) + else: + _commands.append([zone_name, 'dnsrecord_del', args]) + + return _commands + + +def main(): + """Execute DNS record playbook.""" + ansible_module = configure_module() + + global_zone_name = module_params_get(ansible_module, "zone_name") + names = module_params_get(ansible_module, "name") + records = module_params_get(ansible_module, "records") + state = module_params_get(ansible_module, "state") + + # Check parameters + + if (names is None or len(names) < 1) and \ + (records is None or len(records) < 1): + ansible_module.fail_json(msg="One of name and records is required") + + if state == "present": + if names is not None and len(names) != 1: + ansible_module.fail_json( + msg="Only one record can be added at a time.") + + if records is not None: + names = records + + # Init + + changed = False + exit_args = {} + ccache_dir = None + ccache_name = None + + try: + ccache_dir, ccache_name = connect_to_api(ansible_module) + + commands = [] + + for record in names: + if isinstance(record, dict): + # ensure name is a string + zone_name = record.get("zone_name", global_zone_name) + name = record['name'] = str(record['name']) + entry = record + else: + zone_name = global_zone_name + name = record + entry = get_entry_from_module(ansible_module, name) + + check_parameters(ansible_module, state, zone_name, entry) + + res_find = find_dnsrecord(ansible_module, zone_name, name) + + if state == 'present': + cmds = define_commands_for_present_state( + ansible_module, zone_name, entry, res_find) + elif state == 'absent': + cmds = define_commands_for_absent_state( + ansible_module, zone_name, entry, res_find) + else: + ansible_module.fail_json(msg="Unkown state '%s'" % state) + + if cmds: + commands.extend(cmds) + + # Execute commands + for name, command, args in commands: + try: + result = api_command( + ansible_module, command, to_text(name), args) + if "completed" in result: + if result["completed"] > 0: + changed = True + else: + changed = True + + except ipalib.errors.EmptyModlist: + continue + except ipalib.errors.DuplicateEntry: + continue + except Exception as e: + error_message = str(e) + + ansible_module.fail_json( + msg="%s: %s: %s" % (command, name, error_message)) + + except Exception as e: + ansible_module.fail_json(msg=str(e)) + + finally: + temp_kdestroy(ccache_dir, ccache_name) + + # Done + ansible_module.exit_json(changed=changed, host=exit_args) + + +if __name__ == "__main__": + main() diff --git a/tests/dnsrecord/env_cleanup.yml b/tests/dnsrecord/env_cleanup.yml new file mode 100644 index 0000000000000000000000000000000000000000..5b9b7343ff80d9603e91c6c79799054fcb425132 --- /dev/null +++ b/tests/dnsrecord/env_cleanup.yml @@ -0,0 +1,135 @@ +--- + # Cleanup tasks. + - name: Ensure that dns records are absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + del_all: yes + name: + - host01 + - host02 + - host03 + - host04 + - _ftp._tcp + - _sip._udp + state: absent + + - name: Ensure that dns reverse ipv6 records are absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: ip6.arpa. + del_all: yes + name: + - 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f + - 1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f + - 1.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f + - 4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f + - 4.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f + - 4.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f + state: absent + + - name: Ensure that dns reverse ipv6 records are absent (workaround) + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_ipv6_reverse_workaround }}" + del_all: yes + name: + - 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 + - 1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 + - 1.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 + - 4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 + - 4.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 + - 4.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 + state: absent + + - name: Ensure that dns reverse records are absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_24 }}" + name: + - "101" + - "102" + - "103" + - "104" + - "111" + - "112" + - "113" + - "114" + - "121" + - "122" + - "123" + - "124" + del_all: yes + state: absent + + - name: Ensure that dns reverse records are absent (workaround 1) + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_16 }}" + name: + - "101.122" + - "102.122" + - "103.122" + - "104.122" + - "111.122" + - "112.122" + - "113.122" + - "114.122" + - "121.122" + - "122.122" + - "123.122" + - "124.122" + del_all: yes + state: absent + + - name: Ensure that dns reverse records are absent (workaround 2) + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_8 }}" + name: + - "168.101.122" + - "168.102.122" + - "168.103.122" + - "168.104.122" + - "168.111.122" + - "168.112.122" + - "168.113.122" + - "168.114.122" + - "168.121.122" + - "168.122.122" + - "168.123.122" + - "168.124.122" + del_all: yes + state: absent + + - name: Ensure that "{{ safezone }}" dns records are absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + records: + - name: iron01 + del_all: yes + state: absent + + - name: Ensure that NS record for "{{ safezone }}" is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: iron01 + zone_name: "{{ safezone }}" + ns_rec: iron01 + state: absent + + - name: Ensure DNS testing zones are absent. + ipadnszone: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + state: absent + with_items: + - "{{ zone_prefix_reverse }}" + - "{{ zone_prefix_reverse_24 }}" + - "{{ zone_prefix_reverse_16 }}" + - "{{ zone_prefix_reverse_8 }}" + - "{{ testzone }}" + - ip6.arpa. + - d.f.ip6.arpa. + - "{{ safezone }}" diff --git a/tests/dnsrecord/env_setup.yml b/tests/dnsrecord/env_setup.yml new file mode 100644 index 0000000000000000000000000000000000000000..d9a8546b991b99ed51c635e88851558245e64b5a --- /dev/null +++ b/tests/dnsrecord/env_setup.yml @@ -0,0 +1,31 @@ +--- + - name: Setup variables and facts. + include_tasks: env_vars.yml + + # Cleanup before setup. + - name: Cleanup test environment. + include_tasks: env_cleanup.yml + + # Common setup tasks. + - name: Ensure DNS testing zones are present. + ipadnszone: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + skip_nameserver_check: yes + skip_overlap_check: yes + with_items: + - "{{ zone_prefix_reverse }}" + - "{{ zone_prefix_reverse_24 }}" + - "{{ zone_prefix_reverse_16 }}" + - "{{ zone_prefix_reverse_8 }}" + - "{{ testzone }}" + - ip6.arpa. + + - name: Ensure DNSSEC zone '"{{ safezone }}"' is present. + ipadnszone: + ipaadmin_password: SomeADMINpassword + name: "{{ safezone }}" + dnssec: yes + skip_nameserver_check: yes + skip_overlap_check: yes + ignore_errors: yes diff --git a/tests/dnsrecord/env_vars.yml b/tests/dnsrecord/env_vars.yml new file mode 100644 index 0000000000000000000000000000000000000000..bb540a0a9447153f5db7b4fd6126ba19f548f845 --- /dev/null +++ b/tests/dnsrecord/env_vars.yml @@ -0,0 +1,17 @@ +--- +# Set common vars and facts for test. +- name: Set IPv4 address prefix. + set_fact: + ipv4_prefix: '192.168.122' + ipv4_reverse_sufix: '122.168.192' + +- name: Set zone prefixes. + set_fact: + testzone: 'testzone.test' + safezone: 'safezone.test' + zone_ipv6_reverse: "ip6.arpa." + zone_ipv6_reverse_workaround: "d.f.ip6.arpa." + zone_prefix_reverse: "in-addr.arpa" + zone_prefix_reverse_24: "{{ ipv4_prefix.split('.')[::-1] | join ('.') }}.in-addr.arpa" + zone_prefix_reverse_16: "{{ ipv4_prefix.split('.')[1::-1] | join ('.') }}.in-addr.arpa" + zone_prefix_reverse_8: "{{ ipv4_prefix.split('.')[2::-1] | join ('.') }}.in-addr.arpa" diff --git a/tests/dnsrecord/test_compatibility_with_ansible_module.yml b/tests/dnsrecord/test_compatibility_with_ansible_module.yml new file mode 100644 index 0000000000000000000000000000000000000000..e1631135bfff6dde2d9fb43fa9f624fc696e7545 --- /dev/null +++ b/tests/dnsrecord/test_compatibility_with_ansible_module.yml @@ -0,0 +1,234 @@ +--- +- name: Test compatibility with Ansible ipa_dnsrecord module. + hosts: ipaserver + become: true + gather_facts: false + + tasks: + + # setup + - name: Ensure DNS zones to be used are absent. + ipadnszone: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + state: absent + with_items: + - testzone.local + - 2.168.192.in-addr.arpa + + - name: Ensure DNS zones to be used are present. + ipadnszone: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + with_items: + - testzone.local + - 2.168.192.in-addr.arpa + + - name: Ensure that dns record 'host01' is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: testzone.local + record_type: 'AAAA' + record_value: '::1' + state: absent + + - name: Ensure that dns record 'vm-001' is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: vm-001 + zone_name: testzone.local + record_type: 'AAAA' + record_value: '::1' + state: absent + + - name: Ensure a PTR record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: 5 + record_type: 'PTR' + record_value: 'internal.ipa.testzone.local' + zone_name: 2.168.192.in-addr.arpa + state: absent + + - name: Ensure a TXT record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos + record_type: 'TXT' + record_value: 'TESTZONE.LOCAL' + zone_name: testzone.local + state: absent + + - name: Ensure a SRV record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos._udp.testzone.local + record_type: 'SRV' + record_value: '10 50 88 ipa.testzone.local' + zone_name: testzone.local + state: absent + + - name: Ensure an MX record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: '@' + record_type: 'MX' + record_value: '1 mailserver.testzone.local' + zone_name: testzone.local + state: absent + + # tests + - name: Ensure dns record is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: vm-001 + record_type: 'AAAA' + record_value: '::1' + zone_name: testzone.local + state: present + register: result + failed_when: not result.changed + + - name: Ensure that dns record exists with a TTL + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + record_type: 'AAAA' + record_value: '::1' + record_ttl: 300 + zone_name: testzone.local + state: present + register: result + failed_when: not result.changed + + - name: Ensure a PTR record is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: 5 + record_type: 'PTR' + record_value: 'internal.ipa.testzone.local' + zone_name: 2.168.192.in-addr.arpa + state: present + register: result + failed_when: not result.changed + + - name: Ensure a TXT record is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos + record_type: 'TXT' + record_value: 'TESTZONE.LOCAL' + zone_name: testzone.local + state: present + register: result + failed_when: not result.changed + + - name: Ensure a SRV record is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos._udp.testzone.local + record_type: 'SRV' + record_value: '10 50 88 ipa.testzone.local' + zone_name: testzone.local + state: present + register: result + failed_when: not result.changed + + - name: Ensure an MX record is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: '@' + record_type: 'MX' + record_value: '1 mailserver.testzone.local' + zone_name: testzone.local + state: present + register: result + failed_when: not result.changed + + - name: Ensure that dns record is removed + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: testzone.local + record_type: 'AAAA' + record_value: '::1' + state: absent + register: result + failed_when: not result.changed + + # cleanup + - name: Ensure that dns record 'host01' is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: testzone.local + record_type: 'AAAA' + record_value: '::1' + state: absent + register: result + failed_when: result.changed + + - name: Ensure that dns record 'vm-001' is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: vm-001 + zone_name: testzone.local + record_type: 'AAAA' + record_value: '::1' + state: absent + register: result + failed_when: not result.changed + + - name: Ensure a PTR record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: 5 + record_type: 'PTR' + record_value: 'internal.ipa.testzone.local' + zone_name: 2.168.192.in-addr.arpa + state: absent + register: result + failed_when: not result.changed + + - name: Ensure a TXT record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos + record_type: 'TXT' + record_value: 'TESTZONE.LOCAL' + zone_name: testzone.local + state: absent + register: result + failed_when: not result.changed + + - name: Ensure a SRV record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: _kerberos._udp.testzone.local + record_type: 'SRV' + record_value: '10 50 88 ipa.testzone.local' + zone_name: testzone.local + state: absent + register: result + failed_when: not result.changed + + - name: Ensure an MX record is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: '@' + record_type: 'MX' + record_value: '1 mailserver.testzone.local' + zone_name: testzone.local + state: absent + register: result + failed_when: not result.changed + + - name: Ensure DNS zones to be used are absent. + ipadnszone: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + state: absent + with_items: + - testzone.local + - 2.168.192.in-addr.arpa diff --git a/tests/dnsrecord/test_dnsrecord.yml b/tests/dnsrecord/test_dnsrecord.yml new file mode 100644 index 0000000000000000000000000000000000000000..6847e80ea9ca27d5288a4bc2cd29abefc61aab36 --- /dev/null +++ b/tests/dnsrecord/test_dnsrecord.yml @@ -0,0 +1,1348 @@ +--- +- name: Test dnsrecord + hosts: ipaserver + become: yes + gather_facts: yes + + tasks: + + - name: Setup testing environment. + include_tasks: env_setup.yml + + # tests + - name: Ensure that dns record 'host01' is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + record_type: AAAA + record_value: ::1 + register: result + failed_when: not result.changed + + - name: Ensure that dns record 'host01' is present, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + record_type: AAAA + record_value: ::1 + register: result + failed_when: result.changed + + - name: Ensure that dns record 'host02' is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host02 + zone_name: "{{ testzone }}" + record_type: A + record_value: "{{ ipv4_prefix }}.102" + register: result + failed_when: not result.changed + + - name: Ensure that dns record 'host02' is present, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host02 + zone_name: "{{ testzone }}" + record_type: A + record_value: "{{ ipv4_prefix }}.102" + register: result + failed_when: result.changed + + - name: Modify record 'host02' with multiple A and AAAA record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + records: + - name: host02 + zone_name: "{{ testzone }}" + record_type: A + record_value: + - "{{ ipv4_prefix }}.112" + - "{{ ipv4_prefix }}.122" + - name: host02 + zone_name: "{{ testzone }}" + record_type: AAAA + record_value: ::1 + register: result + failed_when: not result.changed + + - name: Modify record 'host02' with multiple A and AAAA record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + records: + - name: host02 + zone_name: "{{ testzone }}" + record_type: A + record_value: + - "{{ ipv4_prefix }}.112" + - "{{ ipv4_prefix }}.122" + - name: host02 + zone_name: "{{ testzone }}" + record_type: AAAA + record_value: ::1 + register: result + failed_when: result.changed + + - name: Ensure 'host02' A6 record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host02 + a6_data: ::1 + register: result + failed_when: not result.changed + + - name: Ensure 'host02' A6 record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host02 + a6_rec: ::1 + register: result + failed_when: result.changed + + - name: Ensure 'host02' A6 record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host02 + a6_rec: ::1 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure 'host02' A6 record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host02 + a6_rec: ::1 + state: absent + register: result + failed_when: result.changed + + - name: Ensure that dns record 'host03' is present, with reverse record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host03 + zone_name: "{{ testzone }}" + a_ip_address: "{{ ipv4_prefix }}.103" + a_create_reverse: yes + register: result + failed_when: not result.changed + + - name: Ensure that dns record 'host03' is present, with reverse record, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host03 + zone_name: "{{ testzone }}" + record_type: A + record_value: "{{ ipv4_prefix }}.103" + create_reverse: yes + register: result + failed_when: result.changed + + - name: Delete all entries associated with host03 + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host03 + del_all: yes + state: absent + register: result + failed_when: not result.changed + + - name: Delete all entries associated with host03, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host03 + del_all: yes + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has CNAME + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + record_type: CNAME + record_value: "host04.{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has CNAME, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cname_hostname: "host04.{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' CNAME is absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cname_rec: "host04.{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' CNAME is absent, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + record_type: CNAME + record_value: "host04.{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' and 'host03' have CNAME, with cname_hostname + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + records: + - name: host04 + cname_hostname: "host04.{{ testzone }}" + - name: host03 + cname_hostname: "host03.{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has CNAME, with cname_hostname, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cname_hostname: "host04.{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' CNAME is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cname_rec: "host04.{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has A record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: "{{ ipv4_prefix }}.104" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has A record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: "{{ ipv4_prefix }}.104" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has the same A record with reverse. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + a_rec: "{{ ipv4_prefix }}.104" + reverse: yes + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has the same A record with reverse, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + a_rec: "{{ ipv4_prefix }}.104" + reverse: yes + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has an A record with reverse, for NS record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: "{{ ipv4_prefix }}.114" + reverse: yes + + - name: Ensure that 'host04' has an A record with reverse, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: "{{ ipv4_prefix }}.114" + reverse: yes + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has AAAA record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + aaaa_ip_address: fd00::0004 + aaaa_create_reverse: yes + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has AAAA record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: fd00::0004 + reverse: yes + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has AAAA record, without reverse. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: fd00::0014 + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' previous AAAA record, now has a reverse record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + aaaa_rec: fd00::0014 + reverse: yes + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' previous AAAA record, now has a reverse record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + aaaa_rec: fd00::0014 + reverse: yes + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has PTR record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_24 }}" + name: "124" + ptr_hostname: "host04.{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has PTR record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_24 }}" + name: "124" + ptr_hostname: "host04.{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has PTR record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_24 }}" + name: "124" + ptr_rec: "host04.{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has PTR record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ zone_prefix_reverse_24 }}" + name: "124" + ptr_rec: "host04.{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has DNAME record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dname_target: "ipa.{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has DNAME record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dname_target: "ipa.{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' DNAME record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dname_rec: "ipa.{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' DNAME record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dname_rec: "ipa.{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has a A record with reverse, for NS record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ip_address: "{{ ipv4_prefix }}.114" + reverse: yes + + - name: Ensure that 'host04' has NS record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ns_hostname: host04 + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has NS record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ns_hostname: host04 + register: result + failed_when: result.changed + + - name: Ensure that 'host04' NS record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ns_rec: host04 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' NS record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + ns_rec: host04 + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' DLV record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dlv_key_tag: 12345 + dlv_algorithm: 3 + dlv_digest_type: 1 + # digest is sha1sum of 'host04."{{ testzone }}"' + dlv_digest: 08ff468cb25ccd21642989294cc33570da5eb2ba + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' DLV record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dlv_key_tag: 12345 + dlv_algorithm: 3 + dlv_digest_type: 1 + dlv_digest: 08ff468cb25ccd21642989294cc33570da5eb2ba + register: result + failed_when: result.changed + + - name: Ensure that 'host04' DLV record is present, with a different key tag. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dlv_key_tag: 54321 + dlv_record: 12345 3 1 08ff468cb25ccd21642989294cc33570da5eb2ba + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' DLV record is present, with a different key tag, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dlv_key_tag: 54321 + dlv_record: 12345 3 1 08ff468cb25ccd21642989294cc33570da5eb2ba + register: result + failed_when: result.changed + + - name: Ensure that 'host04' DLV record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dlv_record: 54321 3 1 08ff468cb25ccd21642989294cc33570da5eb2ba + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' DLV record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + dlv_record: 54321 3 1 08ff468cb25ccd21642989294cc33570da5eb2ba + state: absent + register: result + failed_when: result.changed + + - name: Ensure that dns record 'iron01' is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: iron01 + zone_name: "{{ safezone }}" + ip_address: "{{ ansible_default_ipv4.address }}" + register: result + failed_when: not result.changed + + - name: Ensure that NS record for "{{ safezone }}" is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: iron01 + zone_name: "{{ safezone }}" + ns_hostname: iron01 + register: result + failed_when: not result.changed + + - name: Ensure that 'iron01' DS record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + name: iron01 + ds_key_tag: 12345 + ds_algorithm: 3 + ds_digest_type: 1 + # digest is sha1sum of 'iron01."{{ safezone }}"' + ds_digest: 84763786e4213cca9a6938dba5dacd64f87ec216 + register: result + failed_when: not result.changed + + - name: Ensure that 'iron01' DS record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + name: iron01 + ds_key_tag: 12345 + ds_algorithm: 3 + ds_digest_type: 1 + ds_digest: 84763786e4213cca9a6938dba5dacd64f87ec216 + register: result + failed_when: result.changed + + - name: Ensure that 'iron01' DS record is present, with a different key tag. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + name: iron01 + ds_key_tag: 54321 + ds_rec: 12345 3 1 84763786e4213cca9a6938dba5dacd64f87ec216 + register: result + failed_when: not result.changed + + - name: Ensure that 'iron01' DS record is present, with a different key tag, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + name: iron01 + ds_key_tag: 54321 + ds_rec: 12345 3 1 84763786e4213cca9a6938dba5dacd64f87ec216 + register: result + failed_when: result.changed + + - name: Ensure that 'iron01' DS record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + name: iron01 + ds_rec: 54321 3 1 84763786e4213cca9a6938dba5dacd64f87ec216 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'iron01' DS record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ safezone }}" + name: iron01 + ds_rec: 54321 3 1 84763786e4213cca9a6938dba5dacd64f87ec216 + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' AFSDB record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + afsdb_subtype: 1 + afsdb_hostname: host04."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' AFSDB record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + afsdb_subtype: 1 + afsdb_hostname: host04."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' AFSDB record subtype is 2. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + afsdb_subtype: 2 + afsdb_rec: 1 host04."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' AFSDB record subtype is 2, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + afsdb_subtype: 2 + afsdb_rec: 1 host04."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' AFSDB record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + afsdb_rec: 2 host04."{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' AFSDB record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + afsdb_rec: 2 host04."{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + # Certificate created with: + # - openssl req -x509 -newkey rsa:512 -days 3650 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test' + # - openssl x509 -outform der -in cert1.pem -out cert1.der + # - base64 cert1.der -w5000 + - name: Ensure that 'host04' CERT record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cert_type: 1 + cert_key_tag: 1234 + cert_algorithm: 3 + cert_certificate_or_crl: MIIBdTCCAR+gAwIBAgIUb14+Oug2nPy1fOFF5US+uiJ1LfIwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMDAzMjMxODMzNDNaFw0zMDAzMjExODMzNDNaMA8xDTALBgNVBAMMBHRlc3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAv/yGOgQbtUZbiQMjVly7bWuUX1oBGZAkCvumYpvsep3o1eJJ6HlREbLUlJmgibuNsjqE0FyrXueMjsD8D4juWQIDAQABo1MwUTAdBgNVHQ4EFgQUNtEmJqasXgN7Sh/huB5tx0ONblYwHwYDVR0jBBgwFoAUNtEmJqasXgN7Sh/huB5tx0ONblYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAKhPWPK5+pkT9NLLSZm3ASQJcDkU9asrSoc7MsiHIqSUju/YQgjdHgX0ljS8hnlo1scCITW09UXcNRUYFxwEuoQ= + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' CERT record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cert_type: 1 + cert_key_tag: 1234 + cert_algorithm: 3 + cert_certificate_or_crl: MIIBdTCCAR+gAwIBAgIUb14+Oug2nPy1fOFF5US+uiJ1LfIwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMDAzMjMxODMzNDNaFw0zMDAzMjExODMzNDNaMA8xDTALBgNVBAMMBHRlc3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAv/yGOgQbtUZbiQMjVly7bWuUX1oBGZAkCvumYpvsep3o1eJJ6HlREbLUlJmgibuNsjqE0FyrXueMjsD8D4juWQIDAQABo1MwUTAdBgNVHQ4EFgQUNtEmJqasXgN7Sh/huB5tx0ONblYwHwYDVR0jBBgwFoAUNtEmJqasXgN7Sh/huB5tx0ONblYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAKhPWPK5+pkT9NLLSZm3ASQJcDkU9asrSoc7MsiHIqSUju/YQgjdHgX0ljS8hnlo1scCITW09UXcNRUYFxwEuoQ= + register: result + failed_when: result.changed + + - name: Ensure that 'host04' CERT record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cert_rec: 1 1234 3 MIIBdTCCAR+gAwIBAgIUb14+Oug2nPy1fOFF5US+uiJ1LfIwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMDAzMjMxODMzNDNaFw0zMDAzMjExODMzNDNaMA8xDTALBgNVBAMMBHRlc3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAv/yGOgQbtUZbiQMjVly7bWuUX1oBGZAkCvumYpvsep3o1eJJ6HlREbLUlJmgibuNsjqE0FyrXueMjsD8D4juWQIDAQABo1MwUTAdBgNVHQ4EFgQUNtEmJqasXgN7Sh/huB5tx0ONblYwHwYDVR0jBBgwFoAUNtEmJqasXgN7Sh/huB5tx0ONblYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAKhPWPK5+pkT9NLLSZm3ASQJcDkU9asrSoc7MsiHIqSUju/YQgjdHgX0ljS8hnlo1scCITW09UXcNRUYFxwEuoQ= + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' CERT record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + cert_rec: 1 1234 3 MIIBdTCCAR+gAwIBAgIUb14+Oug2nPy1fOFF5US+uiJ1LfIwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMDAzMjMxODMzNDNaFw0zMDAzMjExODMzNDNaMA8xDTALBgNVBAMMBHRlc3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAv/yGOgQbtUZbiQMjVly7bWuUX1oBGZAkCvumYpvsep3o1eJJ6HlREbLUlJmgibuNsjqE0FyrXueMjsD8D4juWQIDAQABo1MwUTAdBgNVHQ4EFgQUNtEmJqasXgN7Sh/huB5tx0ONblYwHwYDVR0jBBgwFoAUNtEmJqasXgN7Sh/huB5tx0ONblYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAKhPWPK5+pkT9NLLSZm3ASQJcDkU9asrSoc7MsiHIqSUju/YQgjdHgX0ljS8hnlo1scCITW09UXcNRUYFxwEuoQ= + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' KX record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_preference: 10 + kx_exchanger: keyex."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' KX record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_preference: 10 + kx_exchanger: keyex."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' KX record is present with preference set to 20. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_preference: 20 + kx_rec: 10 keyex."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' KX record is present with preference set to 20, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_preference: 20 + kx_rec: 10 keyex."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' KX record is present with preference set to 20, one more time. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_preference: 20 + kx_rec: 20 keyex."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' KX record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_rec: 20 keyex."{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' KX record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + kx_rec: 20 keyex."{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' MX record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + mx_preference: 10 + mx_exchanger: mail."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' MX record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + mx_preference: 10 + mx_exchanger: mail."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that 'host04' MX record is present with preference set to 20. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + mx_preference: 20 + mx_rec: 10 mail."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' MX record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + mx_rec: 20 mail."{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' MX record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + mx_rec: 20 mail."{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + - name: Ensure that '_sip._udp' service has NAPTR record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + record_type: NAPTR + record_value: '100 10 U SIP+D2U !^.*$!sip:customer-service@example.com! .' + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' LOC record is present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + loc_lat_deg: 52 + loc_lat_min: 22 + loc_lat_sec: 23.000 + loc_lat_dir: N + loc_lon_deg: 4 + loc_lon_min: 53 + loc_lon_sec: 32.00 + loc_lon_dir: E + loc_altitude: -2.00 + loc_size: 0.00 + loc_h_precision: 10000 + loc_v_precision: 10 + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' LOC record is present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + loc_lat_deg: 52 + loc_lat_min: 22 + loc_lat_sec: 23.000 + loc_lat_dir: N + loc_lon_deg: 4 + loc_lon_min: 53 + loc_lon_sec: 32.000 + loc_lon_dir: E + loc_altitude: -2.00 + loc_size: 0.00 + loc_h_precision: 10000 + loc_v_precision: 10 + register: result + failed_when: result.changed + + - name: Ensure that 'host04' LOC record is present, with loc_size 1.00. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + loc_size: 1.00 + loc_rec: 52 22 23 N 4 53 32 E -2 0 10000 10 + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' LOC record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + loc_rec: 52 22 23.000 N 4 53 32.000 E -2.00 1.00 10000 10 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' LOC record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + loc_rec: 52 22 23.000 N 4 53 32.000 E -2.00 1.00 10000 10 + state: absent + register: result + failed_when: result.changed + + - name: Ensure that '_sip._udp' service has NAPTR record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + naptr_order: 100 + naptr_preference: 10 + naptr_flags: "U" + naptr_service: "SIP+D2U" + naptr_regexp: "!^.*$!sip:customer-service@example.com!" + naptr_replacement: "." + register: result + failed_when: not result.changed + + - name: Ensure that '_sip._udp' service has NAPTR record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + naptr_order: 100 + naptr_preference: 10 + naptr_flags: "U" + naptr_service: "SIP+D2U" + naptr_regexp: "!^.*$!sip:customer-service@example.com!" + naptr_replacement: "." + register: result + failed_when: result.changed + + - name: Change '_sip._udp' service NAPTR record `preference` to 20. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + naptr_preference: 20 + naptr_rec: '100 10 U SIP+D2U !^.*$!sip:customer-service@example.com! .' + register: result + failed_when: not result.changed + + - name: Ensure that '_sip._udp' service has NAPTR record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + record_type: NAPTR + record_value: '100 20 U SIP+D2U !^.*$!sip:customer-service@example.com! .' + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that '_sip._udp' service has NAPTR record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + record_type: NAPTR + record_value: '100 20 U SIP+D2U !^.*$!sip:customer-service@example.com! .' + state: absent + register: result + failed_when: result.changed + + - name: Ensure that '_sip._udp' service has SRV record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_priority: 10 + srv_weight: 10 + srv_port: 5060 + srv_target: sip-server."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure that '_sip._udp' service has SRV record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_priority: 10 + srv_weight: 10 + srv_port: 5060 + srv_target: sip-server."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure '_sip._udp' SRV record has priority equals to 4. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_priority: 4 + srv_weight: 10 + srv_port: 5060 + srv_target: sip-server."{{ testzone }}" + srv_rec: 10 10 5060 sip-server."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensure '_sip._udp' SRV record has priority equals to 4, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_priority: 4 + srv_weight: 10 + srv_port: 5060 + srv_target: sip-server."{{ testzone }}" + srv_rec: 10 10 5060 sip-server."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensurer '_sip._udp' SRV record has priority 2, weight 20 + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_priority: 2 + srv_weight: 20 + srv_port: 5060 + srv_target: sip-server."{{ testzone }}" + register: result + failed_when: not result.changed + + - name: Ensurer '_sip._udp' SRV record has priority 2, weight 20, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_priority: 2 + srv_weight: 20 + srv_port: 5060 + srv_target: sip-server."{{ testzone }}" + register: result + failed_when: result.changed + + - name: Ensure that '_sip._udp' SRV record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_record: 2 20 5060 sip-server."{{ testzone }}" + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that '_sip._udp' SRV record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _sip._udp + srv_record: 2 20 5060 sip-server."{{ testzone }}" + state: absent + register: result + failed_when: result.changed + + # SSHFP fingerprint generated with `ssh-keygen -r host04."{{ testzone }}"` + - name: Ensure that 'host04' has SSHFP record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + sshfp_algorithm: 1 + sshfp_fp_type: 1 + sshfp_fingerprint: d21802c61733e055b8d16296cbce300efb8a167a + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has SSHFP record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + sshfp_algorithm: 1 + sshfp_fp_type: 1 + sshfp_fingerprint: d21802c61733e055b8d16296cbce300efb8a167a + register: result + failed_when: result.changed + + - name: Ensure that 'host04' SSHFP record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + sshfp_rec: 1 1 d21802c61733e055b8d16296cbce300efb8a167a + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' SSHFP record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + sshfp_rec: 1 1 d21802c61733e055b8d16296cbce300efb8a167a + state: absent + register: result + failed_when: result.changed + + # Data is sha356sum of 'Some Text to Test', it should be created from + # a real certificate. + - name: Ensure that 'host04' has TLSA record present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + tlsa_cert_usage: 3 + tlsa_selector: 1 + tlsa_matching_type: 1 + tlsa_cert_association_data: 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' has TLSA record present, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + tlsa_cert_usage: 3 + tlsa_selector: 1 + tlsa_matching_type: 1 + tlsa_cert_association_data: 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 + register: result + failed_when: result.changed + + - name: Modify 'host04' has TLSA record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + tlsa_matching_type: 0 + tlsa_rec: 3 1 1 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 + register: result + failed_when: not result.changed + + - name: Modify 'host04' has TLSA record, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + tlsa_matching_type: 0 + tlsa_rec: 3 1 1 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 + register: result + failed_when: result.changed + + - name: Ensure that 'host04' TLSA record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + tlsa_rec: 3 1 0 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' TLSA record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + tlsa_rec: 3 1 0 9c0ad776dbeae8d9d55b0ad42899d30235c114d5f918fd69746e4279e47bdaa2 + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' has TXT record present. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_data: Some Text + register: result + failed_when: not result.changed + + # - name: Ensure that 'host04' has TXT record present, again. + # ipadnsrecord: + # ipaadmin_password: SomeADMINpassword + # zone_name: "{{ testzone }}" + # name: host04 + # txt_data: Some Text + # register: result + # failed_when: result.changed + + - name: Change value of 'host04' TXT record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_data: Some new Text + txt_rec: Some Text + register: result + failed_when: not result.changed + + - name: Add a second TXT record to 'host04'. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_rec: Some Other Text + register: result + failed_when: not result.changed + + - name: Add a second TXT record to 'host04', again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_rec: Some Other Text + register: result + failed_when: result.changed + + - name: Ensure that one of 'host04' TXT record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_rec: Some new Text + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that one of 'host04' TXT record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_rec: Some new Text + state: absent + register: result + failed_when: result.changed + + - name: Ensure that 'host04' TXT record are all absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_rec: + - Some new Text + - Some Other Text + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that 'host04' TXT record are all absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: host04 + txt_rec: + - Some new Text + - Some Other Text + state: absent + register: result + failed_when: result.changed + + - name: Ensure that '_ftp._tcp' has URI record. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _ftp._tcp + uri_priority: 10 + uri_weight: 1 + uri_target: ftp://ftp.host04."{{ testzone }}"/public + register: result + failed_when: not result.changed + + - name: Ensure that '_ftp._tcp' has URI record, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _ftp._tcp + uri_priority: 10 + uri_weight: 1 + uri_target: ftp://ftp.host04."{{ testzone }}"/public + register: result + failed_when: result.changed + + - name: Change '_ftp._tcp' URI record weight to 3 and priority to 5. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _ftp._tcp + uri_priority: 5 + uri_weight: 3 + uri_rec: 10 1 ftp://ftp.host04."{{ testzone }}"/public + register: result + failed_when: not result.changed + + - name: Verify if modification worked. + ipadnsrecord: + uri_rec: 10 1 ftp://ftp.host04."{{ testzone }}"/public + state: absent + register: result + failed_when: result.changed + + + - name: Change '_ftp._tcp' URI record weight to 3 and priority to 5, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _ftp._tcp + uri_priority: 5 + uri_weight: 3 + uri_rec: 5 3 ftp://ftp.host04."{{ testzone }}"/public + register: result + failed_when: result.changed + + - name: Ensure that '_ftp._tcp' URI record is absent. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _ftp._tcp + uri_rec: 5 3 ftp://ftp.host04."{{ testzone }}"/public + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that '_ftp._tcp' URI record is absent, again. + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + zone_name: "{{ testzone }}" + name: _ftp._tcp + uri_rec: 5 3 ftp://ftp.host04."{{ testzone }}"/public + state: absent + register: result + failed_when: result.changed + + # cleanup + - name: Cleanup test environment. + include_tasks: env_cleanup.yml diff --git a/tests/dnsrecord/test_dnsrecord_full_records.yml b/tests/dnsrecord/test_dnsrecord_full_records.yml new file mode 100644 index 0000000000000000000000000000000000000000..86e124c882b4415fb93cd217687912e645e0c6d1 --- /dev/null +++ b/tests/dnsrecord/test_dnsrecord_full_records.yml @@ -0,0 +1,150 @@ +--- +- name: Test dnsrecord with full records (*-rec variables). + hosts: ipaserver + become: yes + gather_facts: yes + + tasks: + + - name: Setup test environment + include_tasks: env_setup.yml + + # tests + + - name: Ensure that dns A record for 'host01' is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + a_rec: 192.168.122.101 + register: result + failed_when: not result.changed + + - name: Ensure that dns A record for 'host01' is present, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + a_rec: 192.168.122.101 + register: result + failed_when: result.changed + + - name: Ensure that dns A records for 'host01' are present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + a_rec: + - 192.168.122.101 + - 192.168.122.102 + - 192.168.122.103 + register: result + failed_when: not result.changed + + - name: Ensure that dns A records for 'host01' are present, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + a_rec: + - 192.168.122.101 + - 192.168.122.102 + - 192.168.122.103 + register: result + failed_when: result.changed + + - name: Ensure that dns A records for 'host01' are absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + a_rec: + - 192.168.122.101 + - 192.168.122.102 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that dns A records for 'host01' are absent, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + a_rec: + - 192.168.122.101 + - 192.168.122.102 + state: absent + register: result + failed_when: result.changed + + #### + + - name: Ensure that dns AAAA record for 'host01' is present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + aaaa_rec: fd00::0001 + register: result + failed_when: not result.changed + + - name: Ensure that dns AAAA record for 'host01' is present, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + aaaa_rec: fd00::0001 + register: result + failed_when: result.changed + + - name: Ensure that dns AAAA records for 'host01' are present + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + aaaa_rec: + - fd00::0001 + - fd00::0011 + - fd00::0021 + register: result + failed_when: not result.changed + + - name: Ensure that dns AAAAA records for 'host01' are present, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + aaaa_rec: + - fd00::0001 + - fd00::0011 + - fd00::0021 + register: result + failed_when: result.changed + + - name: Ensure that dns AAAAA records for 'host01' are absent + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + aaaa_rec: + - fd00::0001 + - fd00::0011 + state: absent + register: result + failed_when: not result.changed + + - name: Ensure that dns AAAAA records for 'host01' are absent, again + ipadnsrecord: + ipaadmin_password: SomeADMINpassword + name: host01 + zone_name: "{{ testzone }}" + aaaa_rec: + - fd00::0001 + - fd00::0011 + state: absent + register: result + failed_when: result.changed + + # Cleanup + - name: Cleanup test environment. + include_tasks: env_cleanup.yml