Skip to content
Snippets Groups Projects
Unverified Commit 5a290565 authored by Thomas Woerner's avatar Thomas Woerner Committed by GitHub
Browse files

Merge pull request #235 from rjeffman/dnsrecord

New dnsrecord management module.
parents 40048c78 0abfe8ab
Branches
Tags
No related merge requests found
Showing
with 2255 additions and 0 deletions
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
...@@ -12,6 +12,7 @@ Features ...@@ -12,6 +12,7 @@ Features
* One-time-password (OTP) support for client installation * One-time-password (OTP) support for client installation
* Repair mode for clients * Repair mode for clients
* Modules for dns forwarder management * Modules for dns forwarder management
* Modules for dns record management
* Modules for dns zone management * Modules for dns zone management
* Modules for group management * Modules for group management
* Modules for hbacrule management * Modules for hbacrule management
...@@ -411,6 +412,7 @@ Modules in plugin/modules ...@@ -411,6 +412,7 @@ Modules in plugin/modules
* [ipadnsconfig](README-dnsconfig.md) * [ipadnsconfig](README-dnsconfig.md)
* [ipadnsforwardzone](README-dnsforwardzone.md) * [ipadnsforwardzone](README-dnsforwardzone.md)
* [ipadnsrecord](README-dnsrecord.md)
* [ipadnszone](README-dnszone.md) * [ipadnszone](README-dnszone.md)
* [ipagroup](README-group.md) * [ipagroup](README-group.md)
* [ipahbacrule](README-hbacrule.md) * [ipahbacrule](README-hbacrule.md)
......
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
---
- 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
#!/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()
---
# 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 }}"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment