diff options
Diffstat (limited to 'ipalib')
-rw-r--r-- | ipalib/constants.py | 3 | ||||
-rw-r--r-- | ipalib/errors.py | 16 | ||||
-rw-r--r-- | ipalib/plugins/domainlevel.py | 138 |
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'])} |