On 05/22/2015 03:52 PM, Tomas Babej wrote:


On 05/22/2015 03:32 PM, Petr Vobornik wrote:
On 05/22/2015 03:18 PM, Petr Vobornik wrote:
On 05/22/2015 01:08 PM, Tomas Babej wrote:

snip


1) https://www.redhat.com/archives/freeipa-devel/2015-May/msg00228.html
- I still don't agree that the plugin should be based on LDAPObject.

On the other hand, with LDAPObject base, Web UI for this feature is
much more simpler because it can rely on existing conventions.

IMHO we can swap the approach in a later patch, if we decide it's
necessary. It does not block or relate to other features much.



2) Use api domainlevel-show call to get the current domain level in
ipa-replica-install instead of duplicating the code.
I chose the former approach since the domainlevel_show command doesn't
need to be available, but yeah, this can be properly detected and worked
around too. Fixed.


3) Set the domain level in DSInstance.create_instance instead of a
separate call in ipa-server-install. It should be done about the same
time as the master entry is added.

4) I think the option should be named --domain-level (with a dash), for
consistency.



All other issues fixed.

Updated patch atttached

[36/41]: initializing domain level
   [error] TypeError: __set_domain_level() takes exactly 2 arguments (1
given)
Unexpected error - see /var/log/ipaserver-install.log for details:
TypeError: __set_domain_level() takes exactly 2 arguments (1 given)


Install failed


2. during installation, __set_domain_level is called before the Domain Level entry is created and hence it fails even if the issue above is fixed


Yeah.. we probably need to apply the 72-domainlevel.ldif manually.

Updated patch attached. I ran a successful installation with this patch.

Tomas
From dbea5027ae4fabb4b1149a09d28799bdb4de2eaa Mon Sep 17 00:00:00 2001
From: Tomas Babej <tba...@redhat.com>
Date: Thu, 14 May 2015 10:49:55 +0200
Subject: [PATCH] Add Domain Level feature

https://fedorahosted.org/freeipa/ticket/5018
---
 ACI.txt                                |   2 +
 API.txt                                |  22 ++++++
 install/share/72domainlevels.ldif      |   6 ++
 install/share/Makefile.am              |   2 +
 install/share/domainlevel.ldif         |   7 ++
 install/tools/ipa-replica-install      |  34 +++++++-
 install/tools/ipa-server-install       |  22 +++++-
 install/updates/72-domainlevels.update |  14 ++++
 install/updates/Makefile.am            |   1 +
 ipalib/constants.py                    |   3 +
 ipalib/errors.py                       |  16 ++++
 ipalib/plugins/domainlevel.py          | 137 +++++++++++++++++++++++++++++++++
 ipaserver/install/dsinstance.py        |  12 ++-
 ipaserver/install/ldapupdate.py        |   5 ++
 14 files changed, 273 insertions(+), 10 deletions(-)
 create mode 100644 install/share/72domainlevels.ldif
 create mode 100644 install/share/domainlevel.ldif
 create mode 100644 install/updates/72-domainlevels.update
 create mode 100644 ipalib/plugins/domainlevel.py

diff --git a/ACI.txt b/ACI.txt
index bf539892910f14ebc3fbee88a72d2b57c0d1327b..d38d1c6f5e7f3095704e2c205a52316b4f39f469 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -50,6 +50,8 @@ dn: dc=ipa,dc=example
 aci: (target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Remove DNS Entries";allow (delete) groupdn = "ldap:///cn=System: Remove DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: dc=ipa,dc=example
 aci: (targetattr = "a6record || aaaarecord || afsdbrecord || arecord || certrecord || cn || cnamerecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || ptrrecord || rrsigrecord || sigrecord || srvrecord || sshfprecord || tlsarecord || txtrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Update DNS Entries";allow (write) groupdn = "ldap:///cn=System: Update DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: dc=ipa,dc=example
+aci: (targetattr = "createtimestamp || entryusn || ipadomainlevel || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipadomainlevelconfig)")(version 3.0;acl "permission:System: Read Domain Level";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=groups,cn=accounts,dc=ipa,dc=example
 aci: (targetfilter = "(|(objectclass=ipausergroup)(objectclass=posixgroup))")(version 3.0;acl "permission:System: Add Groups";allow (add) groupdn = "ldap:///cn=System: Add Groups,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=groups,cn=accounts,dc=ipa,dc=example
diff --git a/API.txt b/API.txt
index 0808f3c64595495c8a9e60da5cbd689d5cdc6224..7ee7618a51d8f1ea7a64cddd1e6550616c1cca29 100644
--- a/API.txt
+++ b/API.txt
@@ -1283,6 +1283,28 @@ option: Str('version?', exclude='webui')
 output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: PrimaryKey('value', None, None)
+command: domainlevel_set
+args: 0,8,3
+option: Str('addattr*', cli_name='addattr', exclude='webui')
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('delattr*', cli_name='delattr', exclude='webui')
+option: Int('ipadomainlevel', attribute=True, autofill=False, cli_name='level', minvalue=0, multivalue=False, required=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Flag('rights', autofill=True, default=False)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: domainlevel_show
+args: 0,4,3
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Flag('rights', autofill=True, default=False)
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
 command: env
 args: 1,3,4
 arg: Str('variables*')
diff --git a/install/share/72domainlevels.ldif b/install/share/72domainlevels.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..8473eebb47e1a77fa476f4a7eb1bc04b98fa0813
--- /dev/null
+++ b/install/share/72domainlevels.ldif
@@ -0,0 +1,6 @@
+dn: cn=schema
+attributeTypes: (2.16.840.1.113730.3.8.19.2.1 NAME 'ipaDomainLevel' DESC 'Domain Level value' EQUALITY numericStringMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 SINGLE-VALUE X-ORIGIN 'IPA v4')
+attributeTypes: (2.16.840.1.113730.3.8.19.2.2 NAME 'ipaMinDomainLevel' DESC 'Minimal supported Domain Level value' EQUALITY numericStringMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 SINGLE-VALUE X-ORIGIN 'IPA v4')
+attributeTypes: (2.16.840.1.113730.3.8.19.2.3 NAME 'ipaMaxDomainLevel' DESC 'Maximal supported Domain Level value' EQUALITY numericStringMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 SINGLE-VALUE X-ORIGIN 'IPA v4')
+objectClasses:  (2.16.840.1.113730.3.8.19.1.1  NAME 'ipaDomainLevelConfig' SUP ipaConfigObject AUXILIARY DESC 'Domain Level Configuration' MUST (ipaDomainLevel) X-ORIGIN 'IPA v4')
+objectClasses:  (2.16.840.1.113730.3.8.19.1.2  NAME 'ipaSupportedDomainLevelConfig' SUP ipaConfigObject AUXILIARY DESC 'Supported Domain Level Configuration' MUST (ipaMinDomainLevel $ ipaMaxDomainLevel) X-ORIGIN 'IPA v4')
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index ca6128e2911ab5c0a773dd553f8e67eab944f120..52f7e80d4c4268b965d11c2b64d8e52bb1c533a9 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -21,6 +21,7 @@ app_DATA =				\
 	65ipasudo.ldif			\
 	70ipaotp.ldif			\
 	71idviews.ldif			\
+	72domainlevels.ldif			\
 	anonymous-vlv.ldif		\
 	bootstrap-template.ldif		\
 	caJarSigningCert.cfg.template	\
@@ -33,6 +34,7 @@ app_DATA =				\
 	ds-nfiles.ldif			\
 	dns.ldif			\
 	dnssec.ldif			\
+	domainlevel.ldif			\
 	kerberos.ldif			\
 	indices.ldif			\
 	bind.named.conf.template	\
diff --git a/install/share/domainlevel.ldif b/install/share/domainlevel.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..cb90a6563b29abaf9a74e6d504af26666266d407
--- /dev/null
+++ b/install/share/domainlevel.ldif
@@ -0,0 +1,7 @@
+# Create default Domain Level for new masters
+dn: cn=Domain Level,cn=ipa,cn=etc,$SUFFIX
+changetype: add
+objectClass: top
+objectClass: nsContainer
+objectClass: ipaDomainLevelConfig
+ipaDomainLevel: $DOMAINLEVEL
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index f68cc8cf4722264ecea2f1f50de3aa245be24ef9..a415c293ea6fc2b8c195e6123bbca9686fa0e5e1 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -43,7 +43,7 @@ from ipaserver.install import cainstance
 from ipaserver.install import krainstance
 from ipaserver.install import dns as dns_installer
 from ipalib import api, create_api, errors, util, certstore, x509
-from ipalib.constants import CACERT
+from ipalib import constants
 from ipapython import version
 from ipapython.config import IPAOptionParser
 from ipapython import sysrestore
@@ -224,12 +224,12 @@ def install_ca_cert(ldap, base_dn, realm, cafile):
         try:
             certs = certstore.get_ca_certs(ldap, base_dn, realm, False)
         except errors.NotFound:
-            shutil.copy(cafile, CACERT)
+            shutil.copy(cafile, constants.CACERT)
         else:
             certs = [c[0] for c in certs if c[2] is not False]
-            x509.write_certificate_list(certs, CACERT)
+            x509.write_certificate_list(certs, constants.CACERT)
 
-        os.chmod(CACERT, 0444)
+        os.chmod(constants.CACERT, 0444)
     except Exception, e:
         print "error copying files: " + str(e)
         sys.exit(1)
@@ -569,6 +569,32 @@ def main():
                 print "    %% ipa-replica-manage del %s --force" % config.host_name
                 exit(3)
 
+            # Detect the current domain level
+            try:
+                result = remote_api.Command['domainlevel_show']['result']
+            except KeyError:
+                # If we're joining an older master, domainlevel_show is not
+                # available
+                current = 0
+            else:
+                current = int(result['ipadomainlevel'][0])
+
+            # Detect if current level is out of supported range
+            # for this IPA version
+            under_lower_bound = current < constants.MIN_DOMAIN_LEVEL
+            above_upper_bound = current > constants.MAX_DOMAIN_LEVEL
+
+            if under_lower_bound or above_upper_bound:
+                message = ("This version of FreeIPA does not support "
+                           "the Domain Level which is currently set for "
+                           "this domain. The Domain Level needs to be "
+                           "raised before installing a replica with "
+                           "this version is allowed to be installed "
+                           "within this domain.")
+                root_logger.error(message)
+                print(message)
+                exit(3)
+
             # Check pre-existing host entry
             try:
                 entry = conn.find_entries(u'fqdn=%s' % config.host_name, ['fqdn'], DN(api.env.container_host, api.env.basedn))
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index cb6e1abe2016c0f8cefc35b1d685373f05b3ef89..a62642e78eed19ccf6c678a074475ad3c02c62d6 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -70,7 +70,7 @@ from ipapython import sysrestore
 from ipapython.ipautil import *
 from ipapython import ipautil
 from ipapython import dogtag
-from ipalib import api, errors, util, x509
+from ipalib import api, errors, util, x509, constants
 from ipapython.config import IPAOptionParser
 from ipalib.util import validate_domain_name
 from ipalib.constants import CACERT
@@ -176,6 +176,8 @@ def parse_options():
                            help="create home directories for users "
                                 "on their first login")
     basic_group.add_option("--hostname", dest="host_name", help="fully qualified name of server")
+    basic_group.add_option("--domain-level", dest="domainlevel", help="IPA domain level",
+                           default=constants.MAX_DOMAIN_LEVEL, type=int)
     basic_group.add_option("--ip-address", dest="ip_addresses",
                       type="ip", ip_local=True, action="append", default=[],
                       help="Master Server IP Address. This option can be used multiple times",
@@ -327,6 +329,15 @@ def parse_options():
         except ValueError, e:
             parser.error("invalid domain: " + unicode(e))
 
+    # Check that Domain Level is within the allowed range
+    if not options.uninstall:
+        if options.domainlevel < constants.MIN_DOMAIN_LEVEL:
+            parser.error("Domain Level cannot be lower than {0}"
+                         .format(constants.MIN_DOMAIN_LEVEL))
+        elif options.domainlevel > constants.MAX_DOMAIN_LEVEL:
+            parser.error("Domain Level cannot be higher than {0}"
+                         .format(constants.MAX_DOMAIN_LEVEL))
+
     if not options.setup_dns:
         if options.forwarders:
             parser.error("You cannot specify a --forwarder option without the --setup-dns option")
@@ -1139,21 +1150,24 @@ def main():
                 ntp.create_instance()
 
         if options.dirsrv_cert_files:
-            ds = dsinstance.DsInstance(fstore=fstore)
+            ds = dsinstance.DsInstance(fstore=fstore,
+                                       domainlevel=options.domainlevel)
             ds.create_instance(realm_name, host_name, domain_name,
                             dm_password, dirsrv_pkcs12_info,
                             idstart=options.idstart, idmax=options.idmax,
                             subject_base=options.subject,
                             hbac_allow=not options.hbac_allow)
         else:
-            ds = dsinstance.DsInstance(fstore=fstore)
+            ds = dsinstance.DsInstance(fstore=fstore,
+                                       domainlevel=options.domainlevel)
             ds.create_instance(realm_name, host_name, domain_name,
                             dm_password,
                             idstart=options.idstart, idmax=options.idmax,
                             subject_base=options.subject,
                             hbac_allow=not options.hbac_allow)
     else:
-        ds = dsinstance.DsInstance(fstore=fstore)
+        ds = dsinstance.DsInstance(fstore=fstore,
+                                   domainlevel=options.domainlevel)
         ds.init_info(
             realm_name, host_name, domain_name, dm_password,
             options.subject, 1101, 1100, None)
diff --git a/install/updates/72-domainlevels.update b/install/updates/72-domainlevels.update
new file mode 100644
index 0000000000000000000000000000000000000000..2e83c7be9b200121081470a80a3a9303d685a789
--- /dev/null
+++ b/install/updates/72-domainlevels.update
@@ -0,0 +1,14 @@
+# Create default Domain Level entry if it does not exist
+dn: cn=Domain Level,cn=ipa,cn=etc,$SUFFIX
+default: objectClass: top
+default: objectClass: nsContainer
+default: objectClass: ipaDomainLevelConfig
+default: ipaDomainLevel: 0
+
+# Create entry proclaiming Domain Level support of this master
+# This will update the supported Domain Levels during upgrade
+dn: cn=$FQDN,cn=masters,cn=ipa,cn=etc,$SUFFIX
+add: objectClass: ipaConfigObject
+add: objectClass: ipaSupportedDomainLevelConfig
+only: ipaMinDomainLevel: $MIN_DOMAIN_LEVEL
+only: ipaMaxDomainLevel: $MAX_DOMAIN_LEVEL
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
index 0d63d9ea8d85f1add5f036e7a39f89543586d33b..b52dc2570040336031b7fe01c1cec50156bd90c3 100644
--- a/install/updates/Makefile.am
+++ b/install/updates/Makefile.am
@@ -48,6 +48,7 @@ app_DATA =				\
 	61-trusts-s4u2proxy.update	\
 	62-ranges.update		\
 	71-idviews.update		\
+	72-domainlevels.update		\
 	90-post_upgrade_plugins.update	\
 	$(NULL)
 
diff --git a/ipalib/constants.py b/ipalib/constants.py
index f1e14702ffdf5a3bd23a62b1fdd2ee3cd95d84f8..04e29d25b1b41dbb67c23d02b4a534ec1735e44c 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -223,3 +223,6 @@ LDAP_GENERALIZED_TIME_FORMAT = "%Y%m%d%H%M%SZ"
 
 IPA_ANCHOR_PREFIX = ':IPA:'
 SID_ANCHOR_PREFIX = ':SID:'
+
+MIN_DOMAIN_LEVEL = 0
+MAX_DOMAIN_LEVEL = 1
diff --git a/ipalib/errors.py b/ipalib/errors.py
index 89b1ef2e0dc1d7346a69fb813bd71990746c620c..63ec22269467b769d276c443f6b3dbed38cd766e 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -1344,6 +1344,22 @@ class EmptyResult(NotFound):
 
     errno = 4031
 
+class InvalidDomainLevelError(ExecutionError):
+    """
+    **4032** Raised when a operation could not be completed due to a invalid
+             domain level.
+
+    For example:
+
+    >>> raise InvalidDomainLevelError(reason='feature requires domain level 4')
+    Traceback (most recent call last):
+      ...
+    InvalidDomainLevelError: feature requires domain level 4
+
+    """
+
+    errno = 4032
+
 class BuiltinError(ExecutionError):
     """
     **4100** Base class for builtin execution errors (*4100 - 4199*).
diff --git a/ipalib/plugins/domainlevel.py b/ipalib/plugins/domainlevel.py
new file mode 100644
index 0000000000000000000000000000000000000000..dbc2a5916d39d9b857e40bba45d703db8a076ede
--- /dev/null
+++ b/ipalib/plugins/domainlevel.py
@@ -0,0 +1,137 @@
+#
+# Copyright (C) 2015  FreeIPA Contributors see COPYING for license
+#
+
+from collections import namedtuple
+
+from ipalib import _
+from ipalib import api
+from ipalib import Command
+from ipalib import errors
+from ipalib import output
+from ipalib.parameters import Int
+from ipalib.plugable import Registry
+from ipalib.plugins.baseldap import LDAPObject, LDAPUpdate, LDAPRetrieve
+
+from ipapython.dn import DN
+
+
+__doc__ = _("""
+Raise the IPA Domain Level.
+""")
+
+register = Registry()
+
+DomainLevelRange = namedtuple('DomainLevelRange', ['min', 'max'])
+
+
+@register()
+class domainlevel(LDAPObject):
+    """
+    IPA Domain Level object
+    """
+
+    object_name = _('domain level')
+    default_attributes = [
+        'ipadomainlevel',
+    ]
+
+    permission_filter_objectclasses = ['ipadomainlevelconfig']
+
+    managed_permissions = {
+        'System: Read Domain Level': {
+            'replaces_global_anonymous_aci': True,
+            'ipapermbindruletype': 'all',
+            'ipapermright': {'read', 'search', 'compare'},
+            'ipapermdefaultattr': {
+                'ipadomainlevel', 'objectclass',
+            },
+        },
+    }
+
+    label = _('Domain Level')
+    label_singular = _('Domain Level')
+
+    takes_params = (
+        Int('ipadomainlevel',
+            cli_name='level',
+            label=_('Domain Level'),
+            minvalue=0,
+        ),
+    )
+
+    def get_dn(self, *keys, **kwargs):
+        return DN(('cn', 'Domain Level'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
+
+    def get_domainlevel_range(self, master_entry):
+        try:
+            return DomainLevelRange(
+                int(master_entry['ipaMinDomainLevel'][0]),
+                int(master_entry['ipaMaxDomainLevel'][0])
+            )
+        except KeyError:
+            return DomainLevelRange(0, 0)
+
+    def get_master_entries(self):
+        """
+        Returns list of LDAPEntries representing IPA masters.
+        """
+        ldap = self.backend
+
+        container_masters = DN(
+            ('cn', 'masters'),
+            ('cn', 'ipa'),
+            ('cn', 'etc'),
+            api.env.basedn
+        )
+
+        masters, _ = ldap.find_entries(
+            filter="(cn=*)",
+            base_dn=container_masters,
+            scope=ldap.SCOPE_ONELEVEL,
+            paged_search=True,  # we need to make sure to get all of them
+        )
+
+        return masters
+
+
+@register()
+class domainlevel_set(LDAPUpdate):
+    __doc__ = _('Modify configuration options.')
+
+    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+        """
+        Checks all the IPA masters for supported domain level ranges.
+
+        If the desired domain level is within the supported range of all
+        masters, it will be raised.
+
+        Domain level cannot be lowered.
+        """
+
+        assert isinstance(dn, DN)
+
+        current_value = int(ldap.get_entry(dn)['ipadomainlevel'][0])
+        desired_value = int(entry_attrs['ipadomainlevel'])
+
+        # Domain level cannot be lowered
+        if int(desired_value) < int(current_value):
+            message = _("Domain Level cannot be lowered.")
+            raise errors.InvalidDomainLevelError(message)
+
+        # Check if every master supports the desired level
+        for master in self.obj.get_master_entries():
+            supported = self.obj.get_domainlevel_range(master)
+
+            if supported.min > desired_value or supported.max < desired_value:
+                message = _("Domain Level cannot be raised to {0}, server {1} "
+                            "does not support it."
+                            .format(desired_value, master['cn'][0]))
+                raise errors.InvalidDomainLevelError(message)
+
+        return dn
+
+
+@register()
+class domainlevel_show(LDAPRetrieve):
+    __doc__ = _('Show the current domain level.')
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index f1d24e49d1b184efde1c8d18ff37d0e329037ccc..7005513729628caef784d5fc2138768e8ac817a3 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -61,6 +61,7 @@ IPA_SCHEMA_FILES = ("60kerberos.ldif",
                     "65ipasudo.ldif",
                     "70ipaotp.ldif",
                     "71idviews.ldif",
+                    "72domainlevels.ldif",
                     "15rfc2307bis.ldif",
                     "15rfc4876.ldif")
 
@@ -185,7 +186,7 @@ info: IPA V2.0
 
 class DsInstance(service.Service):
     def __init__(self, realm_name=None, domain_name=None, dm_password=None,
-                 fstore=None):
+                 fstore=None, domainlevel=None):
         service.Service.__init__(self, "dirsrv",
             service_desc="directory server",
             dm_password=dm_password,
@@ -208,6 +209,7 @@ class DsInstance(service.Service):
         self.subject_base = None
         self.open_ports = []
         self.run_init_memberof = True
+        self.domainlevel = domainlevel
         if realm_name:
             self.suffix = ipautil.realm_to_suffix(self.realm)
             self.__setup_sub_dict()
@@ -252,6 +254,7 @@ class DsInstance(service.Service):
     def __common_post_setup(self):
         self.step("initializing group membership", self.init_memberof)
         self.step("adding master entry", self.__add_master_entry)
+        self.step("initializing domain level", self.__set_domain_level)
         self.step("configuring Posix uid/gid generation",
                   self.__config_uidgid_gen)
         self.step("adding replication acis", self.__add_replication_acis)
@@ -392,7 +395,8 @@ class DsInstance(service.Service):
                              IDMAX=self.idmax, HOST=self.fqdn,
                              ESCAPED_SUFFIX=str(self.suffix),
                              GROUP=DS_GROUP,
-                             IDRANGE_SIZE=idrange_size
+                             IDRANGE_SIZE=idrange_size,
+                             DOMAINLEVEL=self.domainlevel,
                          )
 
     def __create_instance(self):
@@ -1002,3 +1006,7 @@ class DsInstance(service.Service):
         root_logger.debug('Unable to find certificate subject base in '
                           'certmap.conf')
         return None
+
+    def __set_domain_level(self):
+        # Create global domain level antry and set the domain level
+        self._ldap_mod("domainlevel.ldif", self.sub_dict)
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index 2f5bcc748eb546b4dad7e1aeeb7a2882a40d8d35..4aa463152b9ec05fb5e1de9e1a5e386f6fc46e6f 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -39,6 +39,7 @@ from ipaserver.install import installutils
 from ipapython import ipautil, ipaldap
 from ipalib import errors
 from ipalib import api, create_api
+from ipalib import constants
 from ipaplatform.paths import paths
 from ipaplatform import services
 from ipapython.dn import DN
@@ -305,6 +306,10 @@ class LDAPUpdate:
             self.sub_dict["TIME"] = int(time.time())
         if not self.sub_dict.get("DOMAIN") and domain is not None:
             self.sub_dict["DOMAIN"] = domain
+        if not self.sub_dict.get("MIN_DOMAIN_LEVEL"):
+            self.sub_dict["MIN_DOMAIN_LEVEL"] = str(constants.MIN_DOMAIN_LEVEL)
+        if not self.sub_dict.get("MAX_DOMAIN_LEVEL"):
+            self.sub_dict["MAX_DOMAIN_LEVEL"] = str(constants.MAX_DOMAIN_LEVEL)
         self.api = create_api(mode=None)
         self.api.bootstrap(in_server=True, context='updates')
         self.api.finalize()
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to