Patch 164 fixes dnszone-mod --allow-dynupdate behavior which  disables
the zone dynamic updates value whenever a dnszone-mod command is run and
--allow-dynupdate options is not set.

I introduced a Param.encode() function (patch 163) to our framework to
help encoding Python native values to LDAP representation more
effectively. True/False to LDAP's "TRUE"/"FALSE" in this case. Encoding
functions are executed in a server context only.

Martin
>From 6e230b1e1638a57a92c8654672bd4cbd7cc560cd Mon Sep 17 00:00:00 2001
From: Martin Kosek <[email protected]>
Date: Wed, 9 Nov 2011 14:10:08 +0100
Subject: [PATCH 1/2] Allow custom server backend encoding

Server framework does not support encoding of native Python type
values stored in Param classes and sub-classes. When backend (LDAP)
value encoding differs from Python type value representation user
has to has to hard-code the encoders in his processing.

This patch introduces a method Param.encode which is used in server
context to encode native Python Param values. The new encode method
is used for Bool parameter to convert native Python bool type value
(True, False) to LDAP value ("TRUE", "FALSE").

https://fedorahosted.org/freeipa/ticket/2039
---
 ipalib/frontend.py         |   10 ++++++++++
 ipalib/parameters.py       |   29 +++++++++++++++++++++++++++++
 ipaserver/plugins/ldap2.py |   17 +++++++++++++++++
 3 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index 61e7f493f8a8e30a1a189d06cd6a69893319deaf..851de4379536e10741d012186b9a914a36923ec7 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -428,6 +428,8 @@ class Command(HasParam):
         if not self.api.env.in_server and 'version' not in params:
             params['version'] = API_VERSION
         self.validate(**params)
+        if self.api.env.in_server:
+            params = self.encode(**params)
         (args, options) = self.params_2_args_options(**params)
         ret = self.run(*args, **options)
         if (
@@ -648,6 +650,14 @@ class Command(HasParam):
             (k, self.params[k].convert(v)) for (k, v) in kw.iteritems()
         )
 
+    def encode(self, **kw):
+        """
+        Return a dictionary of encoded values.
+        """
+        return dict(
+            (k, self.params[k].encode(v)) for (k, v) in kw.iteritems()
+        )
+
     def __convert_iter(self, kw):
         for param in self.params():
             if kw.get(param.name, None) is None:
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index f9e171b0e5fa9590be73f4935b677c2f4447621c..1f3fdfde7452dace6b13a534b9737e8c3b1b0e5d 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -307,6 +307,7 @@ class Param(ReadOnly):
         ('multivalue', bool, False),
         ('primary_key', bool, False),
         ('normalizer', callable, None),
+        ('encoder', callable, None),
         ('default_from', DefaultFrom, None),
         ('create_default', callable, None),
         ('autofill', bool, False),
@@ -768,6 +769,34 @@ class Param(ReadOnly):
                     rule=rule,
                 )
 
+    def encode(self, value):
+        """
+        Encode Python native type value to chosen backend format. Encoding is
+        applied for parameters representing actual attributes (attribute=True).
+
+        The default encode method `Param._encode` can be overriden in a `Param`
+        instance with `encoder` attribute:
+
+        >>> s = Str('my_str', encoder=lambda x:encode(x))
+
+        Note that the default method of encoding values is defined in
+        `Param._encode()`.
+
+        :param value: Encoded value
+        """
+        if not self.attribute: #pylint: disable=E1101
+            return value
+        if self.encoder is not None: #pylint: disable=E1101
+            return self.encoder(value) #pylint: disable=E1101
+
+        return self._encode(value)
+
+    def _encode(self, value):
+        """
+        Encode a value to backend format.
+        """
+        return value
+
     def get_default(self, **kw):
         """
         Return the static default or construct and return a dynamic default.
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index 5c40182933143021abf817bff4ed12287697e4ea..32a1eccb437a1ed3ed74208cdbbb834b3dd1fbc6 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -45,6 +45,7 @@ from ldap.controls import LDAPControl
 from ldap.functions import explode_dn
 from ipalib.dn import DN
 from ipalib import _
+from ipalib.parameters import Bool
 
 import krbV
 
@@ -62,6 +63,22 @@ MEMBERS_INDIRECT = 2
 # SASL authentication mechanism
 SASL_AUTH = _ldap_sasl.sasl({}, 'GSSAPI')
 
+# OID 1.3.6.1.4.1.1466.115.121.1.7 (Boolean) syntax encoding
+def _encode_bool(self, value):
+    def encode_bool_value(value):
+        if value:
+            return u'TRUE'
+        else:
+            return u'FALSE'
+
+    if type(value) in (tuple, list):
+        return tuple(encode_bool_value(v) for v in value)
+    else:
+        return encode_bool_value(value)
+
+# set own Bool parameter encoder
+Bool._encode = _encode_bool
+
 # universal LDAPError handler
 def _handle_errors(e, **kw):
     """
-- 
1.7.6.4

>From 70ee30aa8c906e09582897026014d03cd4579dcf Mon Sep 17 00:00:00 2001
From: Martin Kosek <[email protected]>
Date: Wed, 9 Nov 2011 14:23:15 +0100
Subject: [PATCH 2/2] Fix DNS zone --allow-dynupdate option behavior

--allow-dynupdate was implemented as a Flag parameter type, which
is not convenient for LDAP attributes. When a DNS zone with
permitted dynamic updates was modified and the --allow-dynupdate
flag was not set, dynamic updates were turned off.

This patch changes the option type to Bool parameter type which
behaves according to user expectations when modifying the zone.

https://fedorahosted.org/freeipa/ticket/2039
---
 API.txt                              |    6 +++---
 VERSION                              |    2 +-
 ipalib/plugins/dns.py                |   18 +++++++++---------
 tests/test_xmlrpc/test_dns_plugin.py |    1 -
 4 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/API.txt b/API.txt
index 73c04ffecde24ef8191578f099afdd6d5914fb00..7339cb58c6bac1e6e8f6c7935d008dd3c50816e6 100644
--- a/API.txt
+++ b/API.txt
@@ -867,7 +867,7 @@ option: Int('idnssoaminimum', attribute=True, autofill=True, cli_name='minimum',
 option: Int('dnsttl', attribute=True, cli_name='ttl', label=Gettext('SOA time to live', domain='ipa', localedir=None), multivalue=False, required=False)
 option: StrEnum('dnsclass', attribute=True, cli_name='class', label=Gettext('SOA class', domain='ipa', localedir=None), multivalue=False, required=False, values=(u'IN', u'CS', u'CH', u'HS'))
 option: Str('idnsupdatepolicy', attribute=True, cli_name='update_policy', label=Gettext('BIND update policy', domain='ipa', localedir=None), multivalue=False, required=False)
-option: Flag('idnsallowdynupdate', attribute=True, autofill=True, cli_name='allow_dynupdate', default=False, label=Gettext('Dynamic update', domain='ipa', localedir=None), multivalue=False, required=True)
+option: Bool('idnsallowdynupdate', attribute=True, autofill=True, cli_name='allow_dynupdate', default=False, label=Gettext('Dynamic update', domain='ipa', localedir=None), multivalue=False, required=False)
 option: Str('addattr*', validate_add_attribute, cli_name='addattr', exclude='webui')
 option: Str('setattr*', validate_set_attribute, cli_name='setattr', exclude='webui')
 option: Flag('force', autofill=True, default=False, label=Gettext('Force', domain='ipa', localedir=None))
@@ -912,7 +912,7 @@ option: Int('idnssoaminimum', attribute=True, autofill=False, cli_name='minimum'
 option: Int('dnsttl', attribute=True, autofill=False, cli_name='ttl', label=Gettext('SOA time to live', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
 option: StrEnum('dnsclass', attribute=True, autofill=False, cli_name='class', label=Gettext('SOA class', domain='ipa', localedir=None), multivalue=False, query=True, required=False, values=(u'IN', u'CS', u'CH', u'HS'))
 option: Str('idnsupdatepolicy', attribute=True, autofill=False, cli_name='update_policy', label=Gettext('BIND update policy', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
-option: Bool('idnszoneactive', attribute=True, autofill=False, cli_name='zone_active', default=False, flags=['no_create', 'no_update'], label=Gettext('Active zone', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
+option: Bool('idnszoneactive', attribute=True, autofill=False, cli_name='zone_active', flags=['no_create', 'no_update'], label=Gettext('Active zone', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
 option: Bool('idnsallowdynupdate', attribute=True, autofill=False, cli_name='allow_dynupdate', default=False, label=Gettext('Dynamic update', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
 option: Int('timelimit?', autofill=False, flags=['no_display'], label=Gettext('Time Limit', domain='ipa', localedir=None), minvalue=0)
 option: Int('sizelimit?', autofill=False, flags=['no_display'], label=Gettext('Size Limit', domain='ipa', localedir=None), minvalue=0)
@@ -939,7 +939,7 @@ option: Int('idnssoaminimum', attribute=True, autofill=False, cli_name='minimum'
 option: Int('dnsttl', attribute=True, autofill=False, cli_name='ttl', label=Gettext('SOA time to live', domain='ipa', localedir=None), multivalue=False, required=False)
 option: StrEnum('dnsclass', attribute=True, autofill=False, cli_name='class', label=Gettext('SOA class', domain='ipa', localedir=None), multivalue=False, required=False, values=(u'IN', u'CS', u'CH', u'HS'))
 option: Str('idnsupdatepolicy', attribute=True, autofill=False, cli_name='update_policy', label=Gettext('BIND update policy', domain='ipa', localedir=None), multivalue=False, required=False)
-option: Flag('idnsallowdynupdate', attribute=True, autofill=True, cli_name='allow_dynupdate', default=False, label=Gettext('Dynamic update', domain='ipa', localedir=None), multivalue=False, required=False)
+option: Bool('idnsallowdynupdate', attribute=True, autofill=False, cli_name='allow_dynupdate', default=False, label=Gettext('Dynamic update', domain='ipa', localedir=None), multivalue=False, required=False)
 option: Str('addattr*', validate_add_attribute, cli_name='addattr', exclude='webui')
 option: Str('setattr*', validate_set_attribute, cli_name='setattr', exclude='webui')
 option: Flag('rights', autofill=True, default=False, label=Gettext('Rights', domain='ipa', localedir=None))
diff --git a/VERSION b/VERSION
index 43367b129d652bac3595a1d2b8f0005afadbf7c2..a191c2eed14cd7c93528a35bfeb73a44380834aa 100644
--- a/VERSION
+++ b/VERSION
@@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=14
+IPA_API_VERSION_MINOR=15
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 97eb6a6d4dea2a59baef503ddfce11c1d6bdfd03..06b904dd141df67c151d22b21c4f221cef14fccb 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -23,7 +23,7 @@ import time
 
 from ipalib import api, errors, output
 from ipalib import Command
-from ipalib import Flag, Int, List, Str, StrEnum
+from ipalib import Flag, Bool, Int, List, Str, StrEnum
 from ipalib.plugins.baseldap import *
 from ipalib import _, ngettext
 from ipalib.util import validate_zonemgr
@@ -42,6 +42,10 @@ EXAMPLES:
    ipa dnszone-add example.com --name-server nameserver.example.com
                                --admin-email [email protected]
 
+ Modify the zone to allow dynamic updates for hosts own records in realm EXAMPLE.COM:
+   ipa dnszone-mod example.com --allow-dynupdate=TRUE \\
+        --update-policy="grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM krb5-self * AAAA;"
+
  Add new reverse zone specified by network IP address:
    ipa dnszone-add --name-from-ip 80.142.15.0/24
                    --name-server nameserver.example.com
@@ -395,18 +399,20 @@ class dnszone(LDAPObject):
             label=_('BIND update policy'),
             doc=_('BIND update policy'),
         ),
-        Flag('idnszoneactive?',
+        Bool('idnszoneactive?',
             cli_name='zone_active',
             label=_('Active zone'),
             doc=_('Is zone active?'),
             flags=['no_create', 'no_update'],
             attribute=True,
         ),
-        Flag('idnsallowdynupdate',
+        Bool('idnsallowdynupdate?',
             cli_name='allow_dynupdate',
             label=_('Dynamic update'),
             doc=_('Allow dynamic updates.'),
             attribute=True,
+            default=False,
+            autofill=True
         ),
     )
 
@@ -441,9 +447,6 @@ class dnszone_add(LDAPCreate):
             del entry_attrs['name_from_ip']
 
         entry_attrs['idnszoneactive'] = 'TRUE'
-        entry_attrs['idnsallowdynupdate'] = str(
-            entry_attrs.get('idnsallowdynupdate', False)
-        ).upper()
 
         # Check nameserver has a forward record
         nameserver = entry_attrs['idnssoamname']
@@ -495,9 +498,6 @@ class dnszone_mod(LDAPUpdate):
     def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
         if 'name_from_ip' in entry_attrs:
             del entry_attrs['name_from_ip']
-        entry_attrs['idnsallowdynupdate'] = str(
-            entry_attrs.get('idnsallowdynupdate', False)
-        ).upper()
         return dn
 
 api.register(dnszone_mod)
diff --git a/tests/test_xmlrpc/test_dns_plugin.py b/tests/test_xmlrpc/test_dns_plugin.py
index 679f285d5f053d26c46a400498c51e7bf889eefe..7e75a130ef6306f77e840701dec600ee9fe811bf 100644
--- a/tests/test_xmlrpc/test_dns_plugin.py
+++ b/tests/test_xmlrpc/test_dns_plugin.py
@@ -215,7 +215,6 @@ class test_dns(Declarative):
                     'idnssoaretry': [fuzzy_digits],
                     'idnssoaexpire': [fuzzy_digits],
                     'idnssoaminimum': [fuzzy_digits],
-                    'idnsallowdynupdate': [u'FALSE'],
                 },
             },
         ),
-- 
1.7.6.4

_______________________________________________
Freeipa-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to