Blame plugins/modules/ipadnszone.py

Packit Service 0a38ef
#!/usr/bin/python
Packit Service 0a38ef
# -*- coding: utf-8 -*-
Packit Service 0a38ef
Packit Service 0a38ef
# Authors:
Packit Service 0a38ef
#   Sergio Oliveira Campos <seocam@redhat.com>
Packit Service 0a38ef
#
Packit Service 0a38ef
# Copyright (C) 2020 Red Hat
Packit Service 0a38ef
# see file 'COPYING' for use and warranty information
Packit Service 0a38ef
#
Packit Service 0a38ef
# This program is free software; you can redistribute it and/or modify
Packit Service 0a38ef
# it under the terms of the GNU General Public License as published by
Packit Service 0a38ef
# the Free Software Foundation, either version 3 of the License, or
Packit Service 0a38ef
# (at your option) any later version.
Packit Service 0a38ef
#
Packit Service 0a38ef
# This program is distributed in the hope that it will be useful,
Packit Service 0a38ef
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0a38ef
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 0a38ef
# GNU General Public License for more details.
Packit Service 0a38ef
#
Packit Service 0a38ef
# You should have received a copy of the GNU General Public License
Packit Service 0a38ef
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 0a38ef
Packit Service 0a38ef
ANSIBLE_METADATA = {
Packit Service 0a38ef
    "metadata_version": "1.0",
Packit Service 0a38ef
    "supported_by": "community",
Packit Service 0a38ef
    "status": ["preview"],
Packit Service 0a38ef
}
Packit Service 0a38ef
Packit Service 0a38ef
DOCUMENTATION = """
Packit Service 0a38ef
module: ipadnszone
Packit Service 0a38ef
short description: Manage FreeIPA dnszone
Packit Service 0a38ef
description: Manage FreeIPA dnszone
Packit Service 0a38ef
options:
Packit Service 0a38ef
  ipaadmin_principal:
Packit Service 0a38ef
    description: The admin principal
Packit Service 0a38ef
    default: admin
Packit Service 0a38ef
  ipaadmin_password:
Packit Service 0a38ef
    description: The admin password
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
Packit Service 0a38ef
  name:
Packit Service 0a38ef
    description: The zone name string.
Packit Service 0a38ef
    required: true
Packit Service dd650a
    type: list
Packit Service 0a38ef
    alises: ["zone_name"]
Packit Service 2939af
  name_from_ip:
Packit Service 2939af
    description: |
Packit Service 2939af
      Derive zone name from reverse of IP (PTR).
Packit Service 2939af
      Can only be used with `state: present`.
Packit Service 2939af
    required: false
Packit Service 2939af
    type: str
Packit Service 0a38ef
  forwarders:
Packit Service 0a38ef
    description: The list of global DNS forwarders.
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    options:
Packit Service 0a38ef
      ip_address:
Packit Service 0a38ef
        description: The forwarder nameserver IP address list (IPv4 and IPv6).
Packit Service 0a38ef
        required: true
Packit Service 0a38ef
      port:
Packit Service 0a38ef
        description: The port to forward requests to.
Packit Service 0a38ef
        required: false
Packit Service 0a38ef
  forward_policy:
Packit Service 0a38ef
    description:
Packit Service 0a38ef
      Global forwarding policy. Set to "none" to disable any configured
Packit Service 0a38ef
      global forwarders.
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    choices: ['only', 'first', 'none']
Packit Service 0a38ef
  allow_sync_ptr:
Packit Service 0a38ef
    description:
Packit Service 0a38ef
      Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
  state:
Packit Service 0a38ef
    description: State to ensure
Packit Service 0a38ef
    default: present
Packit Service 0a38ef
    choices: ["present", "absent", "enabled", "disabled"]
Packit Service 0a38ef
  name_server:
Packit Service 0a38ef
    description: Authoritative nameserver domain name
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: str
Packit Service 0a38ef
  admin_email:
Packit Service 0a38ef
    description: Administrator e-mail address
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: str
Packit Service 0a38ef
  update_policy:
Packit Service 0a38ef
    description: BIND update policy
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: str
Packit Service 0a38ef
  dynamic_update:
Packit Service 0a38ef
    description: Allow dynamic updates
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
    alises: ["dynamicupdate"]
Packit Service 0a38ef
  dnssec:
Packit Service 0a38ef
    description: Allow inline DNSSEC signing of records in the zone
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
  allow_transfer:
Packit Service 0a38ef
    description: List of IP addresses or networks which are allowed to transfer the zone
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
  allow_query:
Packit Service 0a38ef
    description: List of IP addresses or networks which are allowed to issue queries
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
  serial:
Packit Service 0a38ef
    description: SOA record serial number
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  refresh:
Packit Service 0a38ef
    description: SOA record refresh time
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  retry:
Packit Service 0a38ef
    description: SOA record retry time
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  expire:
Packit Service 0a38ef
    description: SOA record expire time
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  minimum:
Packit Service 0a38ef
    description: How long should negative responses be cached
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  ttl:
Packit Service 0a38ef
    description: Time to live for records at zone apex
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  default_ttl:
Packit Service 0a38ef
    description: Time to live for records without explicit TTL definition
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: int
Packit Service 0a38ef
  nsec3param_rec:
Packit Service 0a38ef
    description: NSEC3PARAM record for zone in format: hash_algorithm flags iterations salt.
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: str
Packit Service 0a38ef
  skip_overlap_check:
Packit Service 0a38ef
    description: Force DNS zone creation even if it will overlap with an existing zone
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
  skip_nameserver_check:
Packit Service 0a38ef
    description: Force DNS zone creation even if nameserver is not resolvable
Packit Service 0a38ef
    required: false
Packit Service 0a38ef
    type: bool
Packit Service 0a38ef
"""  # noqa: E501
Packit Service 0a38ef
Packit Service 0a38ef
EXAMPLES = """
Packit Service 0a38ef
---
Packit Service 0a38ef
# Ensure the zone is present (very minimal)
Packit Service 0a38ef
- ipadnszone:
Packit Service 0a38ef
    name: test.example.com
Packit Service 0a38ef
Packit Service 0a38ef
# Ensure the zone is present (all available arguments)
Packit Service 0a38ef
- ipadnszone:
Packit Service 0a38ef
    name: test.example.com
Packit Service 0a38ef
    ipaadmin_password: SomeADMINpassword
Packit Service 0a38ef
    allow_sync_ptr: true
Packit Service 0a38ef
    dynamic_update: true
Packit Service 0a38ef
    dnssec: true
Packit Service 0a38ef
    allow_transfer:
Packit Service 0a38ef
      - 1.1.1.1
Packit Service 0a38ef
      - 2.2.2.2
Packit Service 0a38ef
    allow_query:
Packit Service 0a38ef
      - 1.1.1.1
Packit Service 0a38ef
      - 2.2.2.2
Packit Service 0a38ef
    forwarders:
Packit Service 0a38ef
      - ip_address: 8.8.8.8
Packit Service 0a38ef
      - ip_address: 8.8.4.4
Packit Service 0a38ef
        port: 52
Packit Service 0a38ef
    serial: 1234
Packit Service 0a38ef
    refresh: 3600
Packit Service 0a38ef
    retry: 900
Packit Service 0a38ef
    expire: 1209600
Packit Service 0a38ef
    minimum: 3600
Packit Service 0a38ef
    ttl: 60
Packit Service 0a38ef
    default_ttl: 90
Packit Service 0a38ef
    name_server: ipaserver.test.local.
Packit Service 0a38ef
    admin_email: admin.admin@example.com
Packit Service 0a38ef
    nsec3param_rec: "1 7 100 0123456789abcdef"
Packit Service 0a38ef
    skip_overlap_check: true
Packit Service 0a38ef
    skip_nameserver_check: true
Packit Service 0a38ef
    state: present
Packit Service 0a38ef
Packit Service 0a38ef
# Ensure zone is present and disabled
Packit Service 0a38ef
- ipadnszone:
Packit Service 0a38ef
    name: test.example.com
Packit Service 0a38ef
    state: disabled
Packit Service 0a38ef
Packit Service 0a38ef
# Ensure zone is present and enabled
Packit Service 0a38ef
- ipadnszone:
Packit Service 0a38ef
    name: test.example.com
Packit Service 0a38ef
    state: enabled
Packit Service 0a38ef
"""
Packit Service 0a38ef
Packit Service 0a38ef
RETURN = """
Packit Service 2939af
dnszone:
Packit Service 2939af
  description: DNS Zone dict with zone name infered from `name_from_ip`.
Packit Service 2939af
  returned:
Packit Service 2939af
    If `state` is `present`, `name_from_ip` is used, and a zone was created.
Packit Service 2939af
  options:
Packit Service 2939af
    name:
Packit Service 2939af
      description: The name of the zone created, inferred from `name_from_ip`.
Packit Service 2939af
      returned: always
Packit Service 0a38ef
"""
Packit Service 0a38ef
Packit Service 0a38ef
from ipapython.dnsutil import DNSName  # noqa: E402
Packit Service 0a38ef
from ansible.module_utils.ansible_freeipa_module import (
Packit Service 0a38ef
    FreeIPABaseModule,
Packit Service 0a38ef
    is_ipv4_addr,
Packit Service 0a38ef
    is_ipv6_addr,
Packit Service 0a38ef
    is_valid_port,
Packit Service 0a38ef
)  # noqa: E402
Packit Service 2939af
import netaddr
Packit Service 2939af
import six
Packit Service 2939af
Packit Service 2939af
Packit Service 2939af
if six.PY3:
Packit Service 2939af
    unicode = str
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
class DNSZoneModule(FreeIPABaseModule):
Packit Service 0a38ef
Packit Service 0a38ef
    ipa_param_mapping = {
Packit Service 0a38ef
        # Direct Mapping
Packit Service 0a38ef
        "idnsforwardpolicy": "forward_policy",
Packit Service 0a38ef
        "idnssoaserial": "serial",
Packit Service 0a38ef
        "idnssoarefresh": "refresh",
Packit Service 0a38ef
        "idnssoaretry": "retry",
Packit Service 0a38ef
        "idnssoaexpire": "expire",
Packit Service 0a38ef
        "idnssoaminimum": "minimum",
Packit Service 0a38ef
        "dnsttl": "ttl",
Packit Service 0a38ef
        "dnsdefaultttl": "default_ttl",
Packit Service 0a38ef
        "idnsallowsyncptr": "allow_sync_ptr",
Packit Service 0a38ef
        "idnsallowdynupdate": "dynamic_update",
Packit Service 0a38ef
        "idnssecinlinesigning": "dnssec",
Packit Service 0a38ef
        "idnsupdatepolicy": "update_policy",
Packit Service 0a38ef
        # Mapping by method
Packit Service 0a38ef
        "idnsforwarders": "get_ipa_idnsforwarders",
Packit Service 0a38ef
        "idnsallowtransfer": "get_ipa_idnsallowtransfer",
Packit Service 0a38ef
        "idnsallowquery": "get_ipa_idnsallowquery",
Packit Service 0a38ef
        "idnssoamname": "get_ipa_idnssoamname",
Packit Service 0a38ef
        "idnssoarname": "get_ipa_idnssoarname",
Packit Service 0a38ef
        "skip_nameserver_check": "get_ipa_skip_nameserver_check",
Packit Service 0a38ef
        "skip_overlap_check": "get_ipa_skip_overlap_check",
Packit Service 0a38ef
        "nsec3paramrecord": "get_ipa_nsec3paramrecord",
Packit Service 0a38ef
    }
Packit Service 0a38ef
Packit Service 0a38ef
    def validate_ips(self, ips, error_msg):
Packit Service 0a38ef
        invalid_ips = [
Packit Service 0a38ef
            ip for ip in ips if not is_ipv4_addr(ip) or is_ipv6_addr(ip)
Packit Service 0a38ef
        ]
Packit Service 0a38ef
        if any(invalid_ips):
Packit Service 0a38ef
            self.fail_json(msg=error_msg % invalid_ips)
Packit Service 0a38ef
Packit Service 0a38ef
    def is_valid_nsec3param_rec(self, nsec3param_rec):
Packit Service 0a38ef
        try:
Packit Service 0a38ef
            part1, part2, part3, part4 = nsec3param_rec.split(" ")
Packit Service 0a38ef
        except ValueError:
Packit Service 0a38ef
            return False
Packit Service 0a38ef
Packit Service 0a38ef
        if not all([part1.isdigit(), part2.isdigit(), part3.isdigit()]):
Packit Service 0a38ef
            return False
Packit Service 0a38ef
Packit Service 0a38ef
        if not 0 <= int(part1) <= 255:
Packit Service 0a38ef
            return False
Packit Service 0a38ef
Packit Service 0a38ef
        if not 0 <= int(part2) <= 255:
Packit Service 0a38ef
            return False
Packit Service 0a38ef
Packit Service 0a38ef
        if not 0 <= int(part3) <= 65535:
Packit Service 0a38ef
            return False
Packit Service 0a38ef
Packit Service 0a38ef
        try:
Packit Service 0a38ef
            int(part4, 16)
Packit Service 0a38ef
        except ValueError:
Packit Service 0a38ef
            is_hex = False
Packit Service 0a38ef
        else:
Packit Service 0a38ef
            is_hex = True
Packit Service 0a38ef
Packit Service 0a38ef
        even_digits = len(part4) % 2 == 0
Packit Service 0a38ef
        is_dash = part4 == "-"
Packit Service 0a38ef
Packit Service 0a38ef
        # If not hex with even digits or dash then
Packit Service 0a38ef
        #   part4 is invalid
Packit Service 0a38ef
        if not ((is_hex and even_digits) or is_dash):
Packit Service 0a38ef
            return False
Packit Service 0a38ef
Packit Service 0a38ef
        return True
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_nsec3paramrecord(self, **kwargs):
Packit Service 0a38ef
        nsec3param_rec = self.ipa_params.nsec3param_rec
Packit Service 0a38ef
        if nsec3param_rec is not None:
Packit Service 0a38ef
            error_msg = (
Packit Service 0a38ef
                "Invalid nsec3param_rec: %s. "
Packit Service 0a38ef
                "Expected format: <0-255> <0-255> <0-65535> "
Packit Service 0a38ef
                "even-length_hexadecimal_digits_or_hyphen"
Packit Service 0a38ef
            ) % nsec3param_rec
Packit Service 0a38ef
            if not self.is_valid_nsec3param_rec(nsec3param_rec):
Packit Service 0a38ef
                self.fail_json(msg=error_msg)
Packit Service 0a38ef
            return nsec3param_rec
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_idnsforwarders(self, **kwargs):
Packit Service 0a38ef
        if self.ipa_params.forwarders is not None:
Packit Service 0a38ef
            forwarders = []
Packit Service 0a38ef
            for forwarder in self.ipa_params.forwarders:
Packit Service 0a38ef
                ip_address = forwarder.get("ip_address")
Packit Service 0a38ef
                if not (is_ipv4_addr(ip_address) or is_ipv6_addr(ip_address)):
Packit Service 0a38ef
                    self.fail_json(
Packit Service 0a38ef
                        msg="Invalid IP for DNS forwarder: %s" % ip_address
Packit Service 0a38ef
                    )
Packit Service 0a38ef
Packit Service 0a38ef
                port = forwarder.get("port", None)
Packit Service 0a38ef
                if port and not is_valid_port(port):
Packit Service 0a38ef
                    self.fail_json(
Packit Service 0a38ef
                        msg="Invalid port number for DNS forwarder: %s %s"
Packit Service 0a38ef
                        % (ip_address, port)
Packit Service 0a38ef
                    )
Packit Service 0a38ef
                formatted_forwarder = ip_address
Packit Service 0a38ef
                port = forwarder.get("port")
Packit Service 0a38ef
                if port:
Packit Service 0a38ef
                    formatted_forwarder += " port %d" % port
Packit Service 0a38ef
                forwarders.append(formatted_forwarder)
Packit Service 0a38ef
Packit Service 0a38ef
            return forwarders
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_idnsallowtransfer(self, **kwargs):
Packit Service 0a38ef
        if self.ipa_params.allow_transfer is not None:
Packit Service 0a38ef
            error_msg = "Invalid ip_address for DNS allow_transfer: %s"
Packit Service 0a38ef
            self.validate_ips(self.ipa_params.allow_transfer, error_msg)
Packit Service 0a38ef
Packit Service 0a38ef
            return (";".join(self.ipa_params.allow_transfer) or "none") + ";"
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_idnsallowquery(self, **kwargs):
Packit Service 0a38ef
        if self.ipa_params.allow_query is not None:
Packit Service 0a38ef
            error_msg = "Invalid ip_address for DNS allow_query: %s"
Packit Service 0a38ef
            self.validate_ips(self.ipa_params.allow_query, error_msg)
Packit Service 0a38ef
Packit Service 0a38ef
            return (";".join(self.ipa_params.allow_query) or "any") + ";"
Packit Service 0a38ef
Packit Service 0a38ef
    @staticmethod
Packit Service 0a38ef
    def _replace_at_symbol_in_rname(rname):
Packit Service 0a38ef
        """
Packit Service 0a38ef
        See RFC 1035 for more information.
Packit Service 0a38ef
Packit Service 0a38ef
        Section 8. MAIL SUPPORT
Packit Service 0a38ef
        https://tools.ietf.org/html/rfc1035#section-8
Packit Service 0a38ef
        """
Packit Service 0a38ef
        if "@" not in rname:
Packit Service 0a38ef
            return rname
Packit Service 0a38ef
Packit Service 0a38ef
        name, domain = rname.split("@")
Packit Service 0a38ef
        name = name.replace(".", r"\.")
Packit Service 0a38ef
Packit Service 0a38ef
        return ".".join((name, domain))
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_idnssoarname(self, **kwargs):
Packit Service 0a38ef
        if self.ipa_params.admin_email is not None:
Packit Service 0a38ef
            return DNSName(
Packit Service 0a38ef
                self._replace_at_symbol_in_rname(self.ipa_params.admin_email)
Packit Service 0a38ef
            )
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_idnssoamname(self, **kwargs):
Packit Service 0a38ef
        if self.ipa_params.name_server is not None:
Packit Service 0a38ef
            return DNSName(self.ipa_params.name_server)
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_skip_overlap_check(self, **kwargs):
Packit Service dd650a
        zone = kwargs.get('zone')
Packit Service dd650a
        if not zone and self.ipa_params.skip_overlap_check is not None:
Packit Service 0a38ef
            return self.ipa_params.skip_overlap_check
Packit Service 0a38ef
Packit Service dd650a
    def get_ipa_skip_nameserver_check(self, **kwargs):
Packit Service dd650a
        zone = kwargs.get('zone')
Packit Service dd650a
        if not zone and self.ipa_params.skip_nameserver_check is not None:
Packit Service 0a38ef
            return self.ipa_params.skip_nameserver_check
Packit Service 0a38ef
Packit Service 2939af
    def __reverse_zone_name(self, ipaddress):
Packit Service 2939af
        """
Packit Service 2939af
        Infer reverse zone name from an ip address.
Packit Service 2939af
Packit Service 2939af
        This function uses the same heuristics as FreeIPA to infer the zone
Packit Service 2939af
        name from ip.
Packit Service 2939af
        """
Packit Service 2939af
        try:
Packit Service 2939af
            ip = netaddr.IPAddress(str(ipaddress))
Packit Service 2939af
        except (netaddr.AddrFormatError, ValueError):
Packit Service 2939af
            net = netaddr.IPNetwork(ipaddress)
Packit Service 2939af
            items = net.ip.reverse_dns.split('.')
Packit Service 2939af
            prefixlen = net.prefixlen
Packit Service 2939af
            ip_version = net.version
Packit Service 2939af
        else:
Packit Service 2939af
            items = ip.reverse_dns.split('.')
Packit Service 2939af
            prefixlen = 24 if ip.version == 4 else 64
Packit Service 2939af
            ip_version = ip.version
Packit Service 2939af
        if ip_version == 4:
Packit Service 2939af
            return u'.'.join(items[4 - prefixlen // 8:])
Packit Service 2939af
        elif ip_version == 6:
Packit Service 2939af
            return u'.'.join(items[32 - prefixlen // 4:])
Packit Service 2939af
        else:
Packit Service 2939af
            self.fail_json(msg="Invalid IP version for reverse zone.")
Packit Service 2939af
Packit Service 0a38ef
    def get_zone(self, zone_name):
Packit Service 0a38ef
        get_zone_args = {"idnsname": zone_name, "all": True}
Packit Service 0a38ef
        response = self.api_command("dnszone_find", args=get_zone_args)
Packit Service 0a38ef
Packit Service dd650a
        zone = None
Packit Service dd650a
        is_zone_active = False
Packit Service dd650a
Packit Service 0a38ef
        if response["count"] == 1:
Packit Service dd650a
            zone = response["result"][0]
Packit Service dd650a
            is_zone_active = zone.get("idnszoneactive") == ["TRUE"]
Packit Service 0a38ef
Packit Service dd650a
        return zone, is_zone_active
Packit Service dd650a
Packit Service dd650a
    def get_zone_names(self):
Packit Service 2939af
        zone_names = self.__get_zone_names_from_params()
Packit Service 2939af
        if len(zone_names) > 1 and self.ipa_params.state != "absent":
Packit Service dd650a
            self.fail_json(
Packit Service dd650a
                msg=("Please provide a single name. Multiple values for 'name'"
Packit Service dd650a
                     "can only be supplied for state 'absent'.")
Packit Service dd650a
            )
Packit Service 0a38ef
Packit Service 2939af
        return zone_names
Packit Service 2939af
Packit Service 2939af
    def __get_zone_names_from_params(self):
Packit Service 2939af
        if not self.ipa_params.name:
Packit Service 2939af
            return [self.__reverse_zone_name(self.ipa_params.name_from_ip)]
Packit Service 0a38ef
        return self.ipa_params.name
Packit Service 0a38ef
Packit Service 2939af
    def check_ipa_params(self):
Packit Service 2939af
        if not self.ipa_params.name and not self.ipa_params.name_from_ip:
Packit Service 2939af
            self.fail_json(
Packit Service 2939af
                msg="Either `name` or `name_from_ip` must be provided."
Packit Service 2939af
            )
Packit Service 2939af
        if self.ipa_params.state != "present" and self.ipa_params.name_from_ip:
Packit Service 2939af
            self.fail_json(
Packit Service 2939af
                msg=(
Packit Service 2939af
                    "Cannot use argument `name_from_ip` with state `%s`."
Packit Service 2939af
                    % self.ipa_params.state
Packit Service 2939af
                )
Packit Service 2939af
            )
Packit Service 2939af
Packit Service 0a38ef
    def define_ipa_commands(self):
Packit Service dd650a
        for zone_name in self.get_zone_names():
Packit Service dd650a
            # Look for existing zone in IPA
Packit Service dd650a
            zone, is_zone_active = self.get_zone(zone_name)
Packit Service dd650a
            args = self.get_ipa_command_args(zone=zone)
Packit Service dd650a
            just_added = False
Packit Service dd650a
Packit Service dd650a
            if self.ipa_params.state in ["present", "enabled", "disabled"]:
Packit Service dd650a
                if not zone:
Packit Service dd650a
                    # Since the zone doesn't exist we just create it
Packit Service dd650a
                    #   with given args
Packit Service dd650a
                    self.add_ipa_command("dnszone_add", zone_name, args)
Packit Service dd650a
                    is_zone_active = True
Packit Service dd650a
                    just_added = True
Packit Service dd650a
Packit Service dd650a
                else:
Packit Service dd650a
                    # Zone already exist so we need to verify if given args
Packit Service dd650a
                    #   matches the current config. If not we updated it.
Packit Service dd650a
                    if self.require_ipa_attrs_change(args, zone):
Packit Service dd650a
                        self.add_ipa_command("dnszone_mod", zone_name, args)
Packit Service dd650a
Packit Service dd650a
                if self.ipa_params.state == "enabled" and not is_zone_active:
Packit Service dd650a
                    self.add_ipa_command("dnszone_enable", zone_name)
Packit Service dd650a
Packit Service dd650a
                if self.ipa_params.state == "disabled" and is_zone_active:
Packit Service dd650a
                    self.add_ipa_command("dnszone_disable", zone_name)
Packit Service dd650a
Packit Service dd650a
            if self.ipa_params.state == "absent":
Packit Service dd650a
                if zone:
Packit Service dd650a
                    self.add_ipa_command("dnszone_del", zone_name)
Packit Service dd650a
Packit Service dd650a
            # Due to a bug in FreeIPA dnszone-add won't set
Packit Service dd650a
            #   SOA Serial. The good news is that dnszone-mod does the job.
Packit Service dd650a
            # See: https://pagure.io/freeipa/issue/8227
Packit Service dd650a
            # Because of that, if the zone was just added with a given serial
Packit Service dd650a
            #   we run mod just after to workaround the bug
Packit Service dd650a
            if just_added and self.ipa_params.serial is not None:
Packit Service dd650a
                args = {
Packit Service dd650a
                    "idnssoaserial": self.ipa_params.serial,
Packit Service dd650a
                }
Packit Service dd650a
                self.add_ipa_command("dnszone_mod", zone_name, args)
Packit Service 0a38ef
Packit Service 2939af
    def process_command_result(self, name, command, args, result):
Packit Service 2939af
        super(DNSZoneModule, self).process_command_result(
Packit Service 2939af
            name, command, args, result
Packit Service 2939af
        )
Packit Service 2939af
        if command == "dnszone_add" and self.ipa_params.name_from_ip:
Packit Service 2939af
            dnszone_exit_args = self.exit_args.setdefault('dnszone', {})
Packit Service 2939af
            dnszone_exit_args['name'] = name
Packit Service 2939af
Packit Service 0a38ef
Packit Service 0a38ef
def get_argument_spec():
Packit Service 0a38ef
    forwarder_spec = dict(
Packit Service 0a38ef
        ip_address=dict(type=str, required=True),
Packit Service 0a38ef
        port=dict(type=int, required=False, default=None),
Packit Service 0a38ef
    )
Packit Service 0a38ef
Packit Service 0a38ef
    return dict(
Packit Service 0a38ef
        state=dict(
Packit Service 0a38ef
            type="str",
Packit Service 0a38ef
            default="present",
Packit Service 0a38ef
            choices=["present", "absent", "enabled", "disabled"],
Packit Service 0a38ef
        ),
Packit Service 0a38ef
        ipaadmin_principal=dict(type="str", default="admin"),
Packit Service 0a38ef
        ipaadmin_password=dict(type="str", required=False, no_log=True),
Packit Service 0a38ef
        name=dict(
Packit Service 2939af
            type="list", default=None, required=False, aliases=["zone_name"]
Packit Service 0a38ef
        ),
Packit Service 2939af
        name_from_ip=dict(type="str", default=None, required=False),
Packit Service 0a38ef
        forwarders=dict(
Packit Service 0a38ef
            type="list",
Packit Service 0a38ef
            default=None,
Packit Service 0a38ef
            required=False,
Packit Service 0a38ef
            options=dict(**forwarder_spec),
Packit Service 0a38ef
        ),
Packit Service 0a38ef
        forward_policy=dict(
Packit Service 0a38ef
            type="str",
Packit Service 0a38ef
            required=False,
Packit Service 0a38ef
            default=None,
Packit Service 0a38ef
            choices=["only", "first", "none"],
Packit Service 0a38ef
        ),
Packit Service 0a38ef
        name_server=dict(type="str", required=False, default=None),
Packit Service 0a38ef
        admin_email=dict(type="str", required=False, default=None),
Packit Service 0a38ef
        allow_sync_ptr=dict(type="bool", required=False, default=None),
Packit Service 0a38ef
        update_policy=dict(type="str", required=False, default=None),
Packit Service 0a38ef
        dynamic_update=dict(
Packit Service 0a38ef
            type="bool",
Packit Service 0a38ef
            required=False,
Packit Service 0a38ef
            default=None,
Packit Service 0a38ef
            aliases=["dynamicupdate"],
Packit Service 0a38ef
        ),
Packit Service 0a38ef
        dnssec=dict(type="bool", required=False, default=None),
Packit Service 0a38ef
        allow_transfer=dict(type="list", required=False, default=None),
Packit Service 0a38ef
        allow_query=dict(type="list", required=False, default=None),
Packit Service 0a38ef
        serial=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        refresh=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        retry=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        expire=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        minimum=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        ttl=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        default_ttl=dict(type="int", required=False, default=None),
Packit Service 0a38ef
        nsec3param_rec=dict(type="str", required=False, default=None),
Packit Service 0a38ef
        skip_nameserver_check=dict(type="bool", required=False, default=None),
Packit Service 0a38ef
        skip_overlap_check=dict(type="bool", required=False, default=None),
Packit Service 0a38ef
    )
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
def main():
Packit Service 2939af
    DNSZoneModule(
Packit Service 2939af
        argument_spec=get_argument_spec(),
Packit Service 2939af
        mutually_exclusive=[["name", "name_from_ip"]],
Packit Service 2939af
        required_one_of=[["name", "name_from_ip"]],
Packit Service 2939af
    ).ipa_run()
Packit Service 0a38ef
Packit Service 0a38ef
Packit Service 0a38ef
if __name__ == "__main__":
Packit Service 0a38ef
    main()