summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorTomas Babej <tbabej@redhat.com>2015-05-14 10:49:55 +0200
committerJan Cholasta <jcholast@redhat.com>2015-05-26 11:59:47 +0000
commitf3010498af2a4b98512d219b8e09101176c172fe (patch)
treed62ef1b1e718abb0c8565ca84371c2d488686761 /ipalib
parent9eedffdfa62b4fa64244f048969b45b27a995c7a (diff)
downloadfreeipa-f3010498af2a4b98512d219b8e09101176c172fe.tar.gz
freeipa-f3010498af2a4b98512d219b8e09101176c172fe.tar.xz
freeipa-f3010498af2a4b98512d219b8e09101176c172fe.zip
Add Domain Level feature
https://fedorahosted.org/freeipa/ticket/5018 Reviewed-By: Jan Cholasta <jcholast@redhat.com> Reviewed-By: Petr Vobornik <pvoborni@redhat.com>
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/constants.py3
-rw-r--r--ipalib/errors.py16
-rw-r--r--ipalib/plugins/domainlevel.py138
3 files changed, 157 insertions, 0 deletions
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 195938a35..b99306eae 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -224,3 +224,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 89b1ef2e0..63ec22269 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 000000000..64e383006
--- /dev/null
+++ b/ipalib/plugins/domainlevel.py
@@ -0,0 +1,138 @@
+#
+# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
+#
+
+from collections import namedtuple
+
+from ipalib import _
+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'])
+
+domainlevel_output = (
+ output.Output('result', int, _('Current domain level:')),
+)
+
+
+def get_domainlevel_dn(api):
+ domainlevel_dn = DN(
+ ('cn', 'Domain Level'),
+ ('cn', 'ipa'),
+ ('cn', 'etc'),
+ api.env.basedn
+ )
+
+ return domainlevel_dn
+
+
+def get_domainlevel_range(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(ldap, api):
+ """
+ Returns list of LDAPEntries representing IPA masters.
+ """
+
+ 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_get(Command):
+ __doc__ = _('Query current Domain Level.')
+
+ has_output = domainlevel_output
+
+ def execute(self, *args, **options):
+ ldap = self.api.Backend.ldap2
+ entry = ldap.get_entry(
+ get_domainlevel_dn(self.api),
+ ['ipaDomainLevel']
+ )
+
+ return {'result': int(entry.single_value['ipaDomainLevel'])}
+
+
+@register()
+class domainlevel_set(Command):
+ __doc__ = _('Change current Domain Level.')
+
+ has_output = domainlevel_output
+
+ takes_args = (
+ Int('ipadomainlevel',
+ cli_name='level',
+ label=_('Domain Level'),
+ minvalue=0,
+ ),
+ )
+
+ def execute(self, *args, **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.
+ """
+
+ ldap = self.api.Backend.ldap2
+
+ current_entry = ldap.get_entry(get_domainlevel_dn(self.api))
+ current_value = int(current_entry.single_value['ipadomainlevel'])
+ desired_value = int(args[0])
+
+ # 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 get_master_entries(ldap, self.api):
+ supported = 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)
+
+ current_entry.single_value['ipaDomainLevel'] = desired_value
+ ldap.update_entry(current_entry)
+
+ return {'result': int(current_entry.single_value['ipaDomainLevel'])}