On 12/12/14 13:52, Martin Basti wrote:
On 12/12/14 13:50, Martin Kosek wrote:
On 12/11/2014 05:44 PM, Petr Spacek wrote:
On 11.12.2014 16:50, Martin Basti wrote:
Updated aptch attached:


Nice work, ACK!


Can we also add some tests? This is a lot of new code that could break stuff.

We can, in week maybe or after christmas, currently I do some work with tests and adding new tests required by QE, I will add forwardzone warnings tests when finish this.


Added tests (required patch 0170).
Original and new patch attached.

--
Martin Basti

From f1d2f1b8b72934511e50fdd6f8fd72553c43dc58 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Wed, 14 Jan 2015 17:06:56 +0100
Subject: [PATCH] DNS tests: warning if forward zone is inactive

Ticket: https://fedorahosted.org/freeipa/ticket/4721
---
 ipatests/test_xmlrpc/test_dns_plugin.py | 468 ++++++++++++++++++++++++++++++++
 1 file changed, 468 insertions(+)

diff --git a/ipatests/test_xmlrpc/test_dns_plugin.py b/ipatests/test_xmlrpc/test_dns_plugin.py
index dcefd2c6468d2af61dc6e8c5f196909fdc4bfdeb..986204afad6bfef8170aa850fc46d0df0797c699 100644
--- a/ipatests/test_xmlrpc/test_dns_plugin.py
+++ b/ipatests/test_xmlrpc/test_dns_plugin.py
@@ -59,6 +59,21 @@ zone1_permission_dn = DN(('cn',zone1_permission),
                             api.env.container_permission,api.env.basedn)
 zone1_txtrec_dn = DN(('idnsname', '_kerberos'), zone1_dn)
 
+zone1_sub = u'sub.%s' % zone1_absolute
+zone1_sub_dnsname = DNSName(zone1_sub)
+zone1_sub_dn = DN(('idnsname', zone1_sub),
+                  api.env.container_dns, api.env.basedn)
+
+zone1_sub_fw = u'fw.%s' % zone1_sub
+zone1_sub_fw_dnsname = DNSName(zone1_sub_fw)
+zone1_sub_fw_dn = DN(('idnsname', zone1_sub_fw),
+                     api.env.container_dns, api.env.basedn)
+
+zone1_sub2_fw = u'fw.sub2.%s' % zone1_sub
+zone1_sub2_fw_dnsname = DNSName(zone1_sub2_fw)
+zone1_sub2_fw_dn = DN(('idnsname', zone1_sub2_fw),
+                      api.env.container_dns, api.env.basedn)
+
 zone2 = u'zone2.test'
 zone2_dnsname = DNSName(zone2)
 zone2_absolute = u'%s.' % zone2
@@ -4662,3 +4677,456 @@ class test_forward_master_zones_mutual_exlusion(Declarative):
         ),
 
     ]
+
+
+class test_forwardzone_delegation_warnings(Declarative):
+
+    @classmethod
+    def setUpClass(cls):
+        super(test_forwardzone_delegation_warnings, cls).setUpClass()
+
+        if not api.Backend.rpcclient.isconnected():
+            api.Backend.rpcclient.connect(fallback=False)
+
+        if not have_ldap2:
+            raise nose.SkipTest('server plugin not available')
+
+        try:
+            api.Command['dnszone_add'](zone1, idnssoarname=zone1_rname,)
+            api.Command['dnszone_del'](zone1)
+        except errors.NotFound:
+            raise nose.SkipTest('DNS is not configured')
+        except errors.DuplicateEntry:
+            pass
+
+
+    cleanup_commands = [
+        ('dnsforwardzone_del', [zone1_sub_fw, zone1_sub2_fw],
+            {'continue': True}),
+        ('dnszone_del', [zone1, zone1_sub],
+            {'continue': True}),
+    ]
+
+    tests = [
+
+        dict(
+            desc='Create forward zone %r without forwarders with "none" '
+                 'policy' % zone1_sub_fw,
+            command=(
+                'dnsforwardzone_add', [zone1_sub_fw],
+                {'idnsforwardpolicy': u'none'}
+            ),
+            expected={
+                'value': zone1_sub_fw_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_sub_fw_dn,
+                    'idnsname': [zone1_sub_fw_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnsforwardpolicy': [u'none'],
+                    'objectclass': objectclasses.dnsforwardzone,
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Create zone %r (expected warning for %r)' % (zone1,
+                                                               zone1_sub_fw),
+            command=(
+                'dnszone_add', [zone1_absolute], {}
+            ),
+            expected={
+                'value': zone1_absolute_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_dn,
+                    'idnsname': [zone1_absolute_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnssoamname': lambda x: True,  # don't care in this test
+                    'nsrecord': lambda x: True,  # don't care in this test
+                    'idnssoarname': lambda x: True,  # don't care in this test
+                    'idnssoaserial': [fuzzy_digits],
+                    'idnssoarefresh': [fuzzy_digits],
+                    'idnssoaretry': [fuzzy_digits],
+                    'idnssoaexpire': [fuzzy_digits],
+                    'idnssoaminimum': [fuzzy_digits],
+                    'idnsallowdynupdate': [u'FALSE'],
+                    'idnsupdatepolicy': lambda x: True,  # don't care in this test
+                    'idnsallowtransfer': [u'none;'],
+                    'idnsallowquery': [u'any;'],
+                    'objectclass': objectclasses.dnszone,
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                 u'effective because of missing proper NS '
+                                 u'delegation in authoritative zone '
+                                 u'"dnszone.test.". Please add NS record '
+                                 u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Create zone %r (expected warning for %r)' % (zone1_sub,
+                                                               zone1_sub_fw),
+            command=(
+                'dnszone_add', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_sub_dn,
+                    'idnsname': [zone1_sub_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnssoamname': lambda x: True,  # don't care in this test
+                    'nsrecord': lambda x: True,  # don't care in this test
+                    'idnssoarname': lambda x: True,  # don't care in this test
+                    'idnssoaserial': [fuzzy_digits],
+                    'idnssoarefresh': [fuzzy_digits],
+                    'idnssoaretry': [fuzzy_digits],
+                    'idnssoaexpire': [fuzzy_digits],
+                    'idnssoaminimum': [fuzzy_digits],
+                    'idnsallowdynupdate': [u'FALSE'],
+                    'idnsupdatepolicy': lambda x: True,  # don't care in this test
+                    'idnsallowtransfer': [u'none;'],
+                    'idnsallowquery': [u'any;'],
+                    'objectclass': objectclasses.dnszone,
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Disable zone %r (expected warning for %r)' % (zone1_sub,
+                                                                zone1_sub_fw),
+            command=(
+                'dnszone_disable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Disabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Enable zone %r (expected warning for %r)' % (zone1_sub,
+                                                               zone1_sub_fw),
+            command=(
+                'dnszone_enable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Enabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Disable forward zone %r' % (zone1_sub_fw),
+            command=(
+                'dnsforwardzone_disable', [zone1_sub_fw], {}
+            ),
+            expected={
+                'value': zone1_sub_fw_dnsname,
+                'summary': u'Disabled DNS forward zone "%s"' % zone1_sub_fw,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Enable forward zone %r (expected warning for %r)' % (
+                zone1_sub_fw, zone1_sub_fw),
+            command=(
+                'dnsforwardzone_enable', [zone1_sub_fw], {}
+            ),
+            expected={
+                'value': zone1_sub_fw_dnsname,
+                'summary': u'Enabled DNS forward zone "%s"' % zone1_sub_fw,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Delegate zone %r from zone %r using NS record' % (
+                zone1_sub_fw, zone1_sub),
+            command=('dnsrecord_add', [zone1_sub, u'fw'],
+                     {'nsrecord': self_server_ns}),
+            expected={
+                'value': DNSName(u'fw'),
+                'summary': None,
+                'result': {
+                    'objectclass': objectclasses.dnsrecord,
+                    'dn': DN(('idnsname', u'fw'), zone1_sub_dn),
+                    'idnsname': [DNSName(u'fw')],
+                    'nsrecord': [self_server_ns],
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Disable zone %r (expected warning for %r)' % (zone1_sub,
+                                                                zone1_sub_fw),
+            command=(
+                'dnszone_disable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Disabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Enable zone %r' % (zone1_sub),
+            command=(
+                'dnszone_enable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Enabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Delete NS record which delegates zone %r from zone %r '
+                 '(expected warning for %r)' % (zone1_sub_fw,
+                                                zone1_sub, zone1_sub_fw),
+            command=('dnsrecord_del', [zone1_sub, u'fw'],
+                     {'del_all': True}),
+            expected={
+                'value': [DNSName(u'fw')],
+                'summary': u'Deleted record "fw"',
+                'result': {
+                    'failed': [],
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Create forward zone %r without forwarders with "none" '
+                 'policy (expected warning)' % zone1_sub2_fw,
+            command=(
+                'dnsforwardzone_add', [zone1_sub2_fw],
+                {'idnsforwardpolicy': u'none'}
+            ),
+            expected={
+                'value': zone1_sub2_fw_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_sub2_fw_dn,
+                    'idnsname': [zone1_sub2_fw_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnsforwardpolicy': [u'none'],
+                    'objectclass': objectclasses.dnsforwardzone,
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub2.sub.dnszone.test." '
+                                u'is not effective because of missing proper '
+                                u'NS delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw.sub2" to parent zone '
+                                u'"sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Delegate zone %r from zone %r using NS record' % (
+                zone1_sub2_fw, zone1_sub),
+            command=('dnsrecord_add', [zone1_sub, u'fw.sub2'],
+                     {'nsrecord': self_server_ns}),
+            expected={
+                'value': DNSName(u'fw.sub2'),
+                'summary': None,
+                'result': {
+                    'objectclass': objectclasses.dnsrecord,
+                    'dn': DN(('idnsname', u'fw.sub2'), zone1_sub_dn),
+                    'idnsname': [DNSName(u'fw.sub2')],
+                    'nsrecord': [self_server_ns],
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Disable forward zone %r' % (zone1_sub2_fw),
+            command=(
+                'dnsforwardzone_disable', [zone1_sub2_fw], {}
+            ),
+            expected={
+                'value': zone1_sub2_fw_dnsname,
+                'summary': u'Disabled DNS forward zone "%s"' % zone1_sub2_fw,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Enable forward zone %r' % (zone1_sub2_fw),
+            command=(
+                'dnsforwardzone_enable', [zone1_sub2_fw], {}
+            ),
+            expected={
+                'value': zone1_sub2_fw_dnsname,
+                'summary': u'Enabled DNS forward zone "%s"' % zone1_sub2_fw,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Delete zone %r (expected warning for %r, %r)' % (
+                zone1_sub, zone1_sub_fw, zone1_sub2_fw),
+            command=('dnszone_del', [zone1_sub], {}),
+            expected={
+                'value': [zone1_sub_dnsname],
+                'summary': u'Deleted DNS zone "%s"' % zone1_sub,
+                'result': {'failed': []},
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                    {'message': u'forward zone "fw.sub2.sub.dnszone.test." '
+                                 u'is not effective because of missing proper '
+                                 u'NS delegation in authoritative zone '
+                                 u'"dnszone.test.". Please add NS record '
+                                 u'"fw.sub2.sub" to parent zone '
+                                 u'"dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'}
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Delegate zone %r from zone %r using NS record' % (
+                zone1_sub2_fw, zone1),
+            command=('dnsrecord_add', [zone1, u'fw.sub2.sub'],
+                     {'nsrecord': self_server_ns}),
+            expected={
+                'value': DNSName(u'fw.sub2.sub'),
+                'summary': None,
+                'result': {
+                    'objectclass': objectclasses.dnsrecord,
+                    'dn': DN(('idnsname', u'fw.sub2.sub'), zone1_dn),
+                    'idnsname': [DNSName(u'fw.sub2.sub')],
+                    'nsrecord': [self_server_ns],
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Delete (using dnsrecord-mod) NS record which delegates '
+                 'zone %r from zone %r (expected warning for %r)' % (
+                zone1_sub2_fw, zone1, zone1_sub2_fw),
+            command=('dnsrecord_mod', [zone1, u'fw.sub2.sub'],
+                     {'nsrecord': None}),
+            expected={
+                'value': DNSName(u'fw.sub2.sub'),
+                'summary': u'Deleted record "fw.sub2.sub"',
+                'result': {
+                    'failed': [],
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub2.sub.dnszone.test." is '
+                                u'not effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub2.sub" to parent zone '
+                                u'"dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+    ]
-- 
2.1.0

From 30f309635585845b8278ba3d9c4371ae8ec112ed Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Wed, 14 Jan 2015 17:06:56 +0100
Subject: [PATCH] DNS tests: warning if forward zone is inactive

Ticket: https://fedorahosted.org/freeipa/ticket/4721
---
 ipatests/test_xmlrpc/test_dns_plugin.py | 468 ++++++++++++++++++++++++++++++++
 1 file changed, 468 insertions(+)

diff --git a/ipatests/test_xmlrpc/test_dns_plugin.py b/ipatests/test_xmlrpc/test_dns_plugin.py
index 29770e473065190ba5fa6ad7debd54603eeb8379..47251ff68e829a0e0944633bd6243e2c2f79935c 100644
--- a/ipatests/test_xmlrpc/test_dns_plugin.py
+++ b/ipatests/test_xmlrpc/test_dns_plugin.py
@@ -59,6 +59,21 @@ zone1_permission_dn = DN(('cn',zone1_permission),
                             api.env.container_permission,api.env.basedn)
 zone1_txtrec_dn = DN(('idnsname', '_kerberos'), zone1_dn)
 
+zone1_sub = u'sub.%s' % zone1_absolute
+zone1_sub_dnsname = DNSName(zone1_sub)
+zone1_sub_dn = DN(('idnsname', zone1_sub),
+                  api.env.container_dns, api.env.basedn)
+
+zone1_sub_fw = u'fw.%s' % zone1_sub
+zone1_sub_fw_dnsname = DNSName(zone1_sub_fw)
+zone1_sub_fw_dn = DN(('idnsname', zone1_sub_fw),
+                     api.env.container_dns, api.env.basedn)
+
+zone1_sub2_fw = u'fw.sub2.%s' % zone1_sub
+zone1_sub2_fw_dnsname = DNSName(zone1_sub2_fw)
+zone1_sub2_fw_dn = DN(('idnsname', zone1_sub2_fw),
+                      api.env.container_dns, api.env.basedn)
+
 zone2 = u'zone2.test'
 zone2_dnsname = DNSName(zone2)
 zone2_absolute = u'%s.' % zone2
@@ -4662,3 +4677,456 @@ class test_forward_master_zones_mutual_exlusion(Declarative):
         ),
 
     ]
+
+
+class test_forwardzone_delegation_warnings(Declarative):
+
+    @classmethod
+    def setup_class(cls):
+        super(test_forwardzone_delegation_warnings, cls).setup_class()
+
+        if not api.Backend.rpcclient.isconnected():
+            api.Backend.rpcclient.connect(fallback=False)
+
+        if not have_ldap2:
+            raise nose.SkipTest('server plugin not available')
+
+        try:
+            api.Command['dnszone_add'](zone1, idnssoarname=zone1_rname,)
+            api.Command['dnszone_del'](zone1)
+        except errors.NotFound:
+            raise nose.SkipTest('DNS is not configured')
+        except errors.DuplicateEntry:
+            pass
+
+
+    cleanup_commands = [
+        ('dnsforwardzone_del', [zone1_sub_fw, zone1_sub2_fw],
+            {'continue': True}),
+        ('dnszone_del', [zone1, zone1_sub],
+            {'continue': True}),
+    ]
+
+    tests = [
+
+        dict(
+            desc='Create forward zone %r without forwarders with "none" '
+                 'policy' % zone1_sub_fw,
+            command=(
+                'dnsforwardzone_add', [zone1_sub_fw],
+                {'idnsforwardpolicy': u'none'}
+            ),
+            expected={
+                'value': zone1_sub_fw_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_sub_fw_dn,
+                    'idnsname': [zone1_sub_fw_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnsforwardpolicy': [u'none'],
+                    'objectclass': objectclasses.dnsforwardzone,
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Create zone %r (expected warning for %r)' % (zone1,
+                                                               zone1_sub_fw),
+            command=(
+                'dnszone_add', [zone1_absolute], {}
+            ),
+            expected={
+                'value': zone1_absolute_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_dn,
+                    'idnsname': [zone1_absolute_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnssoamname': lambda x: True,  # don't care in this test
+                    'nsrecord': lambda x: True,  # don't care in this test
+                    'idnssoarname': lambda x: True,  # don't care in this test
+                    'idnssoaserial': [fuzzy_digits],
+                    'idnssoarefresh': [fuzzy_digits],
+                    'idnssoaretry': [fuzzy_digits],
+                    'idnssoaexpire': [fuzzy_digits],
+                    'idnssoaminimum': [fuzzy_digits],
+                    'idnsallowdynupdate': [u'FALSE'],
+                    'idnsupdatepolicy': lambda x: True,  # don't care in this test
+                    'idnsallowtransfer': [u'none;'],
+                    'idnsallowquery': [u'any;'],
+                    'objectclass': objectclasses.dnszone,
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                 u'effective because of missing proper NS '
+                                 u'delegation in authoritative zone '
+                                 u'"dnszone.test.". Please add NS record '
+                                 u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Create zone %r (expected warning for %r)' % (zone1_sub,
+                                                               zone1_sub_fw),
+            command=(
+                'dnszone_add', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_sub_dn,
+                    'idnsname': [zone1_sub_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnssoamname': lambda x: True,  # don't care in this test
+                    'nsrecord': lambda x: True,  # don't care in this test
+                    'idnssoarname': lambda x: True,  # don't care in this test
+                    'idnssoaserial': [fuzzy_digits],
+                    'idnssoarefresh': [fuzzy_digits],
+                    'idnssoaretry': [fuzzy_digits],
+                    'idnssoaexpire': [fuzzy_digits],
+                    'idnssoaminimum': [fuzzy_digits],
+                    'idnsallowdynupdate': [u'FALSE'],
+                    'idnsupdatepolicy': lambda x: True,  # don't care in this test
+                    'idnsallowtransfer': [u'none;'],
+                    'idnsallowquery': [u'any;'],
+                    'objectclass': objectclasses.dnszone,
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Disable zone %r (expected warning for %r)' % (zone1_sub,
+                                                                zone1_sub_fw),
+            command=(
+                'dnszone_disable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Disabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Enable zone %r (expected warning for %r)' % (zone1_sub,
+                                                               zone1_sub_fw),
+            command=(
+                'dnszone_enable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Enabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Disable forward zone %r' % (zone1_sub_fw),
+            command=(
+                'dnsforwardzone_disable', [zone1_sub_fw], {}
+            ),
+            expected={
+                'value': zone1_sub_fw_dnsname,
+                'summary': u'Disabled DNS forward zone "%s"' % zone1_sub_fw,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Enable forward zone %r (expected warning for %r)' % (
+                zone1_sub_fw, zone1_sub_fw),
+            command=(
+                'dnsforwardzone_enable', [zone1_sub_fw], {}
+            ),
+            expected={
+                'value': zone1_sub_fw_dnsname,
+                'summary': u'Enabled DNS forward zone "%s"' % zone1_sub_fw,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Delegate zone %r from zone %r using NS record' % (
+                zone1_sub_fw, zone1_sub),
+            command=('dnsrecord_add', [zone1_sub, u'fw'],
+                     {'nsrecord': self_server_ns}),
+            expected={
+                'value': DNSName(u'fw'),
+                'summary': None,
+                'result': {
+                    'objectclass': objectclasses.dnsrecord,
+                    'dn': DN(('idnsname', u'fw'), zone1_sub_dn),
+                    'idnsname': [DNSName(u'fw')],
+                    'nsrecord': [self_server_ns],
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Disable zone %r (expected warning for %r)' % (zone1_sub,
+                                                                zone1_sub_fw),
+            command=(
+                'dnszone_disable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Disabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Enable zone %r' % (zone1_sub),
+            command=(
+                'dnszone_enable', [zone1_sub], {}
+            ),
+            expected={
+                'value': zone1_sub_dnsname,
+                'summary': u'Enabled DNS zone "%s"' % zone1_sub,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Delete NS record which delegates zone %r from zone %r '
+                 '(expected warning for %r)' % (zone1_sub_fw,
+                                                zone1_sub, zone1_sub_fw),
+            command=('dnsrecord_del', [zone1_sub, u'fw'],
+                     {'del_all': True}),
+            expected={
+                'value': [DNSName(u'fw')],
+                'summary': u'Deleted record "fw"',
+                'result': {
+                    'failed': [],
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw" to parent zone "sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Create forward zone %r without forwarders with "none" '
+                 'policy (expected warning)' % zone1_sub2_fw,
+            command=(
+                'dnsforwardzone_add', [zone1_sub2_fw],
+                {'idnsforwardpolicy': u'none'}
+            ),
+            expected={
+                'value': zone1_sub2_fw_dnsname,
+                'summary': None,
+                'result': {
+                    'dn': zone1_sub2_fw_dn,
+                    'idnsname': [zone1_sub2_fw_dnsname],
+                    'idnszoneactive': [u'TRUE'],
+                    'idnsforwardpolicy': [u'none'],
+                    'objectclass': objectclasses.dnsforwardzone,
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub2.sub.dnszone.test." '
+                                u'is not effective because of missing proper '
+                                u'NS delegation in authoritative zone '
+                                u'"sub.dnszone.test.". Please add NS record '
+                                u'"fw.sub2" to parent zone '
+                                u'"sub.dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Delegate zone %r from zone %r using NS record' % (
+                zone1_sub2_fw, zone1_sub),
+            command=('dnsrecord_add', [zone1_sub, u'fw.sub2'],
+                     {'nsrecord': self_server_ns}),
+            expected={
+                'value': DNSName(u'fw.sub2'),
+                'summary': None,
+                'result': {
+                    'objectclass': objectclasses.dnsrecord,
+                    'dn': DN(('idnsname', u'fw.sub2'), zone1_sub_dn),
+                    'idnsname': [DNSName(u'fw.sub2')],
+                    'nsrecord': [self_server_ns],
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Disable forward zone %r' % (zone1_sub2_fw),
+            command=(
+                'dnsforwardzone_disable', [zone1_sub2_fw], {}
+            ),
+            expected={
+                'value': zone1_sub2_fw_dnsname,
+                'summary': u'Disabled DNS forward zone "%s"' % zone1_sub2_fw,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Enable forward zone %r' % (zone1_sub2_fw),
+            command=(
+                'dnsforwardzone_enable', [zone1_sub2_fw], {}
+            ),
+            expected={
+                'value': zone1_sub2_fw_dnsname,
+                'summary': u'Enabled DNS forward zone "%s"' % zone1_sub2_fw,
+                'result': True,
+            },
+        ),
+
+
+        dict(
+            desc='Delete zone %r (expected warning for %r, %r)' % (
+                zone1_sub, zone1_sub_fw, zone1_sub2_fw),
+            command=('dnszone_del', [zone1_sub], {}),
+            expected={
+                'value': [zone1_sub_dnsname],
+                'summary': u'Deleted DNS zone "%s"' % zone1_sub,
+                'result': {'failed': []},
+                'messages': (
+                    {'message': u'forward zone "fw.sub.dnszone.test." is not '
+                                u'effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub" to parent zone "dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                    {'message': u'forward zone "fw.sub2.sub.dnszone.test." '
+                                 u'is not effective because of missing proper '
+                                 u'NS delegation in authoritative zone '
+                                 u'"dnszone.test.". Please add NS record '
+                                 u'"fw.sub2.sub" to parent zone '
+                                 u'"dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'}
+                ),
+            },
+        ),
+
+
+        dict(
+            desc='Delegate zone %r from zone %r using NS record' % (
+                zone1_sub2_fw, zone1),
+            command=('dnsrecord_add', [zone1, u'fw.sub2.sub'],
+                     {'nsrecord': self_server_ns}),
+            expected={
+                'value': DNSName(u'fw.sub2.sub'),
+                'summary': None,
+                'result': {
+                    'objectclass': objectclasses.dnsrecord,
+                    'dn': DN(('idnsname', u'fw.sub2.sub'), zone1_dn),
+                    'idnsname': [DNSName(u'fw.sub2.sub')],
+                    'nsrecord': [self_server_ns],
+                },
+            },
+        ),
+
+
+        dict(
+            desc='Delete (using dnsrecord-mod) NS record which delegates '
+                 'zone %r from zone %r (expected warning for %r)' % (
+                zone1_sub2_fw, zone1, zone1_sub2_fw),
+            command=('dnsrecord_mod', [zone1, u'fw.sub2.sub'],
+                     {'nsrecord': None}),
+            expected={
+                'value': DNSName(u'fw.sub2.sub'),
+                'summary': u'Deleted record "fw.sub2.sub"',
+                'result': {
+                    'failed': [],
+                },
+                'messages': (
+                    {'message': u'forward zone "fw.sub2.sub.dnszone.test." is '
+                                u'not effective because of missing proper NS '
+                                u'delegation in authoritative zone '
+                                u'"dnszone.test.". Please add NS record '
+                                u'"fw.sub2.sub" to parent zone '
+                                u'"dnszone.test.".',
+                     'code': 13008,
+                     'type': u'warning',
+                     'name': u'ForwardzoneIsNotEffectiveWarning'},
+                ),
+            },
+        ),
+
+    ]
-- 
2.1.0

From c85d7639e62ca5871e0598db973c9540b056b197 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Fri, 21 Nov 2014 16:54:09 +0100
Subject: [PATCH] Detect and warn about invalid DNS forward zone configuration

Shows warning if forward and parent authoritative zone do not have
proper NS record delegation, which can cause the forward zone will be
ineffective and forwarding will not work.

Ticket: https://fedorahosted.org/freeipa/ticket/4721
---
 ipalib/messages.py    |  13 ++
 ipalib/plugins/dns.py | 330 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 332 insertions(+), 11 deletions(-)

diff --git a/ipalib/messages.py b/ipalib/messages.py
index 102e35275dbe37328c84ecb3cd5b2a8d8578056f..b44beca729f5483a7241e4c98a9f724ed663e70f 100644
--- a/ipalib/messages.py
+++ b/ipalib/messages.py
@@ -200,6 +200,19 @@ class DNSServerDoesNotSupportDNSSECWarning(PublicMessage):
                u"If DNSSEC validation is enabled on IPA server(s), "
                u"please disable it.")
 
+class ForwardzoneIsNotEffectiveWarning(PublicMessage):
+    """
+    **13008** Forwardzone is not effective, forwarding will not work because
+    there is authoritative parent zone, without proper NS delegation
+    """
+
+    errno = 13008
+    type = "warning"
+    format = _(u"forward zone \"%(fwzone)s\" is not effective because of "
+               u"missing proper NS delegation in authoritative zone "
+               u"\"%(authzone)s\". Please add NS record "
+               u"\"%(ns_rec)s\" to parent zone \"%(authzone)s\".")
+
 
 def iter_messages(variables, base):
     """Return a tuple with all subclasses
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 34afc189866993481229bb68a5edd77e0a4eaff3..7a80036c94432a01ea8781101712ea1135134948 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -1733,6 +1733,239 @@ def _normalize_zone(zone):
     return zone
 
 
+def _get_auth_zone_ldap(name):
+    """
+    Find authoritative zone in LDAP for name. Only active zones are considered.
+    :param name:
+    :return: (zone, truncated)
+    zone: authoritative zone, or None if authoritative zone is not in LDAP
+    """
+    assert isinstance(name, DNSName)
+    ldap = api.Backend.ldap2
+
+    # Create all possible parent zone names
+    search_name = name.make_absolute()
+    zone_names = []
+    for i in xrange(len(search_name)):
+        zone_name_abs = DNSName(search_name[i:]).ToASCII()
+        zone_names.append(zone_name_abs)
+        # compatibility with IPA < 4.0, zone name can be relative
+        zone_names.append(zone_name_abs[:-1])
+
+    # Create filters
+    objectclass_filter = ldap.make_filter({'objectclass':'idnszone'})
+    zonenames_filter = ldap.make_filter({'idnsname': zone_names})
+    zoneactive_filter = ldap.make_filter({'idnsZoneActive': 'true'})
+    complete_filter = ldap.combine_filters(
+        [objectclass_filter, zonenames_filter, zoneactive_filter],
+        rules=ldap.MATCH_ALL
+    )
+
+    try:
+        entries, truncated = ldap.find_entries(
+            filter=complete_filter,
+            attrs_list=['idnsname'],
+            base_dn=DN(api.env.container_dns, api.env.basedn),
+            scope=ldap.SCOPE_ONELEVEL
+        )
+    except errors.NotFound:
+        return None, False
+
+    # always use absolute zones
+    matched_auth_zones = [entry.single_value['idnsname'].make_absolute()
+                          for entry in entries]
+
+    # return longest match
+    return max(matched_auth_zones, key=len), truncated
+
+
+def _get_longest_match_ns_delegation_ldap(zone, name):
+    """
+    Searches for deepest delegation for name in LDAP zone.
+
+    NOTE: NS record in zone apex is not considered as delegation.
+    It returns None if there is no delegation outside of zone apex.
+
+    Example:
+    zone: example.com.
+    name: ns.sub.example.com.
+
+    records:
+        extra.ns.sub.example.com.
+        sub.example.com.
+        example.com
+
+    result: sub.example.com.
+
+    :param zone: zone name
+    :param name:
+    :return: (match, truncated);
+    match: delegation name if success, or None if no delegation record exists
+    """
+    assert isinstance(zone, DNSName)
+    assert isinstance(name, DNSName)
+
+    ldap = api.Backend.ldap2
+
+    # get zone DN
+    zone_dn = api.Object.dnszone.get_dn(zone)
+
+    if name.is_absolute():
+        relative_record_name = name.relativize(zone.make_absolute())
+    else:
+        relative_record_name = name
+
+    # Name is zone apex
+    if relative_record_name.is_empty():
+        return None, False
+
+    # create list of possible record names
+    possible_record_names = [DNSName(relative_record_name[i:]).ToASCII()
+                             for i in xrange(len(relative_record_name))]
+
+    # search filters
+    name_filter = ldap.make_filter({'idnsname': [possible_record_names]})
+    objectclass_filter = ldap.make_filter({'objectclass': 'idnsrecord'})
+    complete_filter = ldap.combine_filters(
+        [name_filter, objectclass_filter],
+        rules=ldap.MATCH_ALL
+    )
+
+    try:
+        entries, truncated = ldap.find_entries(
+            filter=complete_filter,
+            attrs_list=['idnsname', 'nsrecord'],
+            base_dn=zone_dn,
+            scope=ldap.SCOPE_ONELEVEL
+        )
+    except errors.NotFound:
+        return None, False
+
+    matched_records = []
+
+    # test if entry contains NS records
+    for entry in entries:
+        if entry.get('nsrecord'):
+            matched_records.append(entry.single_value['idnsname'])
+
+    if not matched_records:
+        return None, truncated
+
+    # return longest match
+    return max(matched_records, key=len), truncated
+
+
+def _find_subtree_forward_zones_ldap(name, child_zones_only=False):
+    """
+    Search for forwardzone <name> and all child forwardzones
+    Filter: (|(*.<name>.)(<name>.))
+    :param name:
+    :param child_zones_only: search only for child zones
+    :return: (list of zonenames,  truncated), list is empty if no zone found
+    """
+    assert isinstance(name, DNSName)
+    ldap = api.Backend.ldap2
+
+    # prepare for filter "*.<name>."
+    search_name = u".%s" % name.make_absolute().ToASCII()
+
+    # we need to search zone with and without last dot, due compatibility
+    # with IPA < 4.0
+    search_names = [search_name, search_name[:-1]]
+
+    # Create filters
+    objectclass_filter = ldap.make_filter({'objectclass':'idnsforwardzone'})
+    zonenames_filter = ldap.make_filter({'idnsname': search_names}, exact=False,
+                                        trailing_wildcard=False)
+    if not child_zones_only:
+        # find also zone with exact name
+        exact_name = name.make_absolute().ToASCII()
+        # we need to search zone with and without last dot, due compatibility
+        # with IPA < 4.0
+        exact_names = [exact_name, exact_name[-1]]
+        exact_name_filter = ldap.make_filter({'idnsname': exact_names})
+        zonenames_filter = ldap.combine_filters([zonenames_filter,
+                                                 exact_name_filter])
+
+    zoneactive_filter = ldap.make_filter({'idnsZoneActive': 'true'})
+    complete_filter = ldap.combine_filters(
+        [objectclass_filter, zonenames_filter, zoneactive_filter],
+        rules=ldap.MATCH_ALL
+    )
+
+    try:
+        entries, truncated = ldap.find_entries(
+            filter=complete_filter,
+            attrs_list=['idnsname'],
+            base_dn=DN(api.env.container_dns, api.env.basedn),
+            scope=ldap.SCOPE_ONELEVEL
+        )
+    except errors.NotFound:
+        return [], False
+
+    result = [entry.single_value['idnsname'].make_absolute()
+              for entry in entries]
+
+    return result, truncated
+
+
+def _get_zone_which_makes_fw_zone_ineffective(fwzonename):
+    """
+    Check if forward zone is effective.
+
+    If parent zone exists as authoritative zone, the forward zone will not
+    forward queries by default. It is necessary to delegate authority
+    to forward zone with a NS record.
+
+    Example:
+
+    Forward zone: sub.example.com
+    Zone: example.com
+
+    Forwarding will not work, because the server thinks it is authoritative
+    for zone and will return NXDOMAIN
+
+    Adding record: sub.example.com NS ns.sub.example.com.
+    will delegate authority, and IPA DNS server will forward DNS queries.
+
+    :param fwzonename: forwardzone
+    :return: (zone, truncated)
+    zone: None if effective, name of authoritative zone otherwise
+    """
+    assert isinstance(fwzonename, DNSName)
+
+    auth_zone, truncated_zone = _get_auth_zone_ldap(fwzonename)
+    if not auth_zone:
+        return None, truncated_zone
+
+    delegation_record_name, truncated_ns =\
+        _get_longest_match_ns_delegation_ldap(auth_zone, fwzonename)
+
+    truncated = truncated_ns or truncated_zone
+
+    if delegation_record_name:
+        return None, truncated
+
+    return auth_zone, truncated
+
+
+def _add_warning_fw_zone_is_not_effective(result, fwzone, version):
+    """
+    Adds warning message to result, if required
+    """
+    authoritative_zone, truncated = \
+        _get_zone_which_makes_fw_zone_ineffective(fwzone)
+    if authoritative_zone:
+        # forward zone is not effective and forwarding will not work
+        messages.add_message(
+            version, result,
+            messages.ForwardzoneIsNotEffectiveWarning(
+                fwzone=fwzone, authzone=authoritative_zone,
+                ns_rec=fwzone.relativize(authoritative_zone)
+            )
+        )
+
+
 class DNSZoneBase(LDAPObject):
     """
     Base class for DNS Zone
@@ -2384,6 +2617,22 @@ class dnszone(DNSZoneBase):
                 )
             )
 
+    def _warning_fw_zone_is_not_effective(self, result, *keys, **options):
+        """
+        Warning if any operation with zone causes, a child forward zone is
+        not effective
+        """
+        zone = keys[-1]
+        affected_fw_zones, truncated = _find_subtree_forward_zones_ldap(
+            zone, child_zones_only=True)
+        if not affected_fw_zones:
+            return
+
+        for fwzone in affected_fw_zones:
+            _add_warning_fw_zone_is_not_effective(result, fwzone,
+                                                  options['version'])
+
+
 @register()
 class dnszone_add(DNSZoneBase_add):
     __doc__ = _('Create new DNS zone (SOA record).')
@@ -2453,6 +2702,7 @@ class dnszone_add(DNSZoneBase_add):
         self.obj._warning_forwarding(result, **options)
         self.obj._warning_dnssec_experimental(result, *keys, **options)
         self.obj._warning_name_server_option(result, context, **options)
+        self.obj._warning_fw_zone_is_not_effective(result, *keys, **options)
         return result
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
@@ -2483,6 +2733,13 @@ class dnszone_del(DNSZoneBase_del):
 
     msg_summary = _('Deleted DNS zone "%(value)s"')
 
+    def execute(self, *keys, **options):
+        result = super(dnszone_del, self).execute(*keys, **options)
+        nkeys = keys[-1]  # we can delete more zones
+        for key in nkeys:
+            self.obj._warning_fw_zone_is_not_effective(result, key, **options)
+        return result
+
     def post_callback(self, ldap, dn, *keys, **options):
         super(dnszone_del, self).post_callback(ldap, dn, *keys, **options)
 
@@ -2603,12 +2860,22 @@ class dnszone_disable(DNSZoneBase_disable):
     __doc__ = _('Disable DNS Zone.')
     msg_summary = _('Disabled DNS zone "%(value)s"')
 
+    def execute(self, *keys, **options):
+        result = super(dnszone_disable, self).execute(*keys, **options)
+        self.obj._warning_fw_zone_is_not_effective(result, *keys, **options)
+        return result
+
 
 @register()
 class dnszone_enable(DNSZoneBase_enable):
     __doc__ = _('Enable DNS Zone.')
     msg_summary = _('Enabled DNS zone "%(value)s"')
 
+    def execute(self, *keys, **options):
+        result = super(dnszone_enable, self).execute(*keys, **options)
+        self.obj._warning_fw_zone_is_not_effective(result, *keys, **options)
+        return result
+
 
 @register()
 class dnszone_add_permission(DNSZoneBase_add_permission):
@@ -3172,6 +3439,25 @@ class dnsrecord(LDAPObject):
             dns_name = entry_name[1].derelativize(dns_domain)
             self.wait_for_modified_attrs(entry, dns_name, dns_domain)
 
+    def warning_if_ns_change_cause_fwzone_ineffective(self, result, *keys,
+                                                      **options):
+        """Detect if NS record change can make forward zones ineffective due
+        missing delegation. Run after parent's execute method.
+        """
+        record_name_absolute = keys[-1]
+        zone = keys[-2]
+
+        if not record_name_absolute.is_absolute():
+            record_name_absolute = record_name_absolute.derelativize(zone)
+
+        affected_fw_zones, truncated = _find_subtree_forward_zones_ldap(
+            record_name_absolute)
+        if not affected_fw_zones:
+            return
+
+        for fwzone in affected_fw_zones:
+            _add_warning_fw_zone_is_not_effective(result, fwzone,
+                                                  options['version'])
 
 
 @register()
@@ -3495,7 +3781,10 @@ class dnsrecord_mod(LDAPUpdate):
 
         if self.api.env['wait_for_dns']:
             self.obj.wait_for_modified_entries(context.dnsrecord_entry_mods)
-
+        if 'nsrecord' in options:
+            self.obj.warning_if_ns_change_cause_fwzone_ineffective(result,
+                                                                   *keys,
+                                                                   **options)
         return result
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
@@ -3662,19 +3951,23 @@ class dnsrecord_del(LDAPUpdate):
             if self.api.env['wait_for_dns']:
                 entries = {(keys[0], keys[1]): None}
                 self.obj.wait_for_modified_entries(entries)
-            return result
+        else:
+            result = super(dnsrecord_del, self).execute(*keys, **options)
+            result['value'] = pkey_to_value([keys[-1]], options)
 
-        result = super(dnsrecord_del, self).execute(*keys, **options)
-        result['value'] = pkey_to_value([keys[-1]], options)
+            if getattr(context, 'del_all', False) and not \
+                    self.obj.is_pkey_zone_record(*keys):
+                result = self.obj.methods.delentry(*keys,
+                                                   version=options['version'])
+                context.dnsrecord_entry_mods[(keys[0], keys[1])] = None
 
-        if getattr(context, 'del_all', False) and not \
-                self.obj.is_pkey_zone_record(*keys):
-            result = self.obj.methods.delentry(*keys,
-                                               version=options['version'])
-            context.dnsrecord_entry_mods[(keys[0], keys[1])] = None
+            if self.api.env['wait_for_dns']:
+                self.obj.wait_for_modified_entries(context.dnsrecord_entry_mods)
 
-        if self.api.env['wait_for_dns']:
-            self.obj.wait_for_modified_entries(context.dnsrecord_entry_mods)
+        if 'nsrecord' in options or options.get('del_all', False):
+            self.obj.warning_if_ns_change_cause_fwzone_ineffective(result,
+                                                                   *keys,
+                                                                   **options)
         return result
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
@@ -4006,6 +4299,11 @@ class dnsforwardzone(DNSZoneBase):
     # managed_permissions: permissions was apllied in dnszone class, do NOT
     # add them here, they should not be applied twice.
 
+    def _warning_fw_zone_is_not_effective(self, result, *keys, **options):
+        fwzone = keys[-1]
+        _add_warning_fw_zone_is_not_effective(result, fwzone,
+                                              options['version'])
+
 
 @register()
 class dnsforwardzone_add(DNSZoneBase_add):
@@ -4027,6 +4325,11 @@ class dnsforwardzone_add(DNSZoneBase_add):
 
         return dn
 
+    def execute(self, *keys, **options):
+        result = super(dnsforwardzone_add, self).execute(*keys, **options)
+        self.obj._warning_fw_zone_is_not_effective(result, *keys, **options)
+        return result
+
 
 @register()
 class dnsforwardzone_del(DNSZoneBase_del):
@@ -4091,6 +4394,11 @@ class dnsforwardzone_enable(DNSZoneBase_enable):
     __doc__ = _('Enable DNS Forward Zone.')
     msg_summary = _('Enabled DNS forward zone "%(value)s"')
 
+    def execute(self, *keys, **options):
+        result = super(dnsforwardzone_enable, self).execute(*keys, **options)
+        self.obj._warning_fw_zone_is_not_effective(result, *keys, **options)
+        return result
+
 
 @register()
 class dnsforwardzone_add_permission(DNSZoneBase_add_permission):
-- 
1.8.3.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to