IPA 3.0 introduced range ID objects in replicated space which specify a range of IDs assigned via DNA plugin. ipa-ldap-updater generates the default ID range which should correspond with IDs assigned to IPA users.
However, since correct range size is not known, we should at least warn that a range with invalid size was created so that user can amend it. I created 2 new tickets to add further improve this area: 1) #2918: [doc] Upgrade procedure section should mention ipa-ldap-updater 2) #2919: Improve safety checks in range command To test this patch, you can: 1) Install unpatched IPA server (and you may install replicas too) with custom --idstart and --idmax options where difference is greater then 200000 2) Remove default range with range-del command (will be restored during upgrade) 3) Run RPM upgrade with RPMs built from patched sources - ERROR should now be printed during update stating that a new range was created but its size is not right Martin
>From a61488b5fa77ed983c8de11d211ebb56d2337fee Mon Sep 17 00:00:00 2001 From: Martin Kosek <mko...@redhat.com> Date: Wed, 11 Jul 2012 14:09:17 +0200 Subject: [PATCH 1/3] Add range-mod command range plugin was missing range-mod command that could be used for example to fix a size for a range generated during upgrades. The range should be updated with a caution though, a misconfiguration could break trusts. iparangetype is now also handled better and filled in all commands instead of just range-show. objectclass attribute is deleted only when really needed now. --- API.txt | 19 +++++++++++++++ VERSION | 2 +- ipalib/plugins/range.py | 41 +++++++++++++++++++++++++++----- tests/test_xmlrpc/test_range_plugin.py | 23 ++++++++++++++++-- 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/API.txt b/API.txt index 54313404142129a863792c67b706262973a268d6..691a9c4dec69f1006e52eafd3a94e351750165b7 100644 --- a/API.txt +++ b/API.txt @@ -2411,6 +2411,25 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None)) output: Output('count', <type 'int'>, None) output: Output('truncated', <type 'bool'>, None) +command: range_mod +args: 1,13,3 +arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True) +option: Int('ipabaseid', attribute=True, autofill=False, cli_name='base_id', multivalue=False, required=False) +option: Int('ipaidrangesize', attribute=True, autofill=False, cli_name='range_size', multivalue=False, required=False) +option: Int('ipabaserid', attribute=True, autofill=False, cli_name='rid_base', multivalue=False, required=False) +option: Int('ipasecondarybaserid', attribute=True, autofill=False, cli_name='secondary_rid_base', multivalue=False, required=False) +option: Str('ipanttrusteddomainsid', attribute=True, autofill=False, cli_name='dom_sid', multivalue=False, required=False) +option: Str('iparangetype', attribute=True, autofill=False, cli_name='iparangetype', multivalue=False, required=False) +option: Str('setattr*', cli_name='setattr', exclude='webui') +option: Str('addattr*', cli_name='addattr', exclude='webui') +option: Str('delattr*', cli_name='delattr', exclude='webui') +option: Flag('rights', autofill=True, default=False) +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: Str('version?', exclude='webui') +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None) +output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) +output: Output('value', <type 'unicode'>, None) command: range_show args: 1,4,3 arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True) diff --git a/VERSION b/VERSION index 542dd5fcaa6627711cb59f93d1a7585f6a02241a..8d9efe6573bd148f2e74961c6ce7247f9bc3393d 100644 --- a/VERSION +++ b/VERSION @@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=39 +IPA_API_VERSION_MINOR=40 diff --git a/ipalib/plugins/range.py b/ipalib/plugins/range.py index 4448aad818ea4c9065c387e11035e165d52e4328..39849b661e35cc9092221b3d2bf7d13fb27f506c 100644 --- a/ipalib/plugins/range.py +++ b/ipalib/plugins/range.py @@ -80,6 +80,16 @@ class range(LDAPObject): ) ) + def handle_iparangetype(self, entry_attrs, options, keep_objectclass=False): + if not options.get('pkey_only', False): + if 'ipatrustedaddomainrange' in entry_attrs.get('objectclass', []): + entry_attrs['iparangetype'] = [unicode(_('Active Directory domain range'))] + else: + entry_attrs['iparangetype'] = [unicode(_(u'local domain range'))] + if not keep_objectclass: + if not options.get('all', False) or options.get('pkey_only', False): + entry_attrs.pop('objectclass', None) + class range_add(LDAPCreate): __doc__ = _('Add new ID range.') @@ -99,6 +109,10 @@ class range_add(LDAPCreate): return dn + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + self.obj.handle_iparangetype(entry_attrs, options, keep_objectclass=True) + return dn + class range_del(LDAPDelete): __doc__ = _('Delete an ID range.') @@ -114,8 +128,14 @@ class range_find(LDAPSearch): # Since all range types are stored within separate containers under # 'cn=ranges,cn=etc' search can be done on a one-level scope def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): + attrs_list.append('objectclass') return (filters, base_dn, ldap.SCOPE_ONELEVEL) + def post_callback(self, ldap, entries, truncated, *args, **options): + for dn,entry in entries: + self.obj.handle_iparangetype(entry, options) + return truncated + class range_show(LDAPRetrieve): __doc__ = _('Display information about a range.') @@ -124,16 +144,25 @@ class range_show(LDAPRetrieve): return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - if 'ipatrustedaddomainrange' in entry_attrs['objectclass']: - entry_attrs['iparangetype']=(u'Active Directory domain range') - else: - entry_attrs['iparangetype']=(u'local domain range') - del entry_attrs['objectclass'] + self.obj.handle_iparangetype(entry_attrs, options) + return dn + +class range_mod(LDAPUpdate): + __doc__ = _('Modify ID range.') + + msg_summary = _('Modified ID range "%(value)s"') + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + attrs_list.append('objectclass') + return dn + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + self.obj.handle_iparangetype(entry_attrs, options) return dn api.register(range) api.register(range_add) -#api.register(range_mod) +api.register(range_mod) api.register(range_del) api.register(range_find) api.register(range_show) diff --git a/tests/test_xmlrpc/test_range_plugin.py b/tests/test_xmlrpc/test_range_plugin.py index 7c95cd57a4a2fdd91862a7659cb2aac19c5edfcc..76ffc58b724e50529b8617f7d2d96923342eb0d8 100644 --- a/tests/test_xmlrpc/test_range_plugin.py +++ b/tests/test_xmlrpc/test_range_plugin.py @@ -49,7 +49,8 @@ class test_range(Declarative): ipabaseid=[u'900000'], ipabaserid=[u'1000'], ipasecondarybaserid=[u'20000'], - ipaidrangesize=[u'99999'] + ipaidrangesize=[u'99999'], + iparangetype=[u'local domain range'], ), value=testrange1, summary=u'Added ID range "%s"' % (testrange1), @@ -69,11 +70,29 @@ class test_range(Declarative): ipabaserid=[u'1000'], ipasecondarybaserid=[u'20000'], ipaidrangesize=[u'99999'], - iparangetype=u'local domain range', + iparangetype=[u'local domain range'], ), value=testrange1, summary=None, ), ), + + dict( + desc='Modify range %r' % (testrange1), + command=('range_mod', [testrange1], dict(ipaidrangesize=90000)), + expected=dict( + result=dict( + cn=[testrange1], + ipabaseid=[u'900000'], + ipabaserid=[u'1000'], + ipasecondarybaserid=[u'20000'], + ipaidrangesize=[u'90000'], + iparangetype=[u'local domain range'], + ), + value=testrange1, + summary=u'Modified ID range "%s"' % (testrange1), + ), + ), + ] -- 1.7.10.4
>From 78ce0c8d0b44c051cbb82e1fbb62bf114c0c39a8 Mon Sep 17 00:00:00 2001 From: Martin Kosek <mko...@redhat.com> Date: Wed, 11 Jul 2012 16:13:25 +0200 Subject: [PATCH 2/3] Warn user if an ID range with incorrect size was created IPA 3.0 introduced range ID objects in replicated space which specify a range of IDs assigned via DNA plugin. ipa-ldap-updater generates the default ID range which should correspond with IDs assigned to IPA users. However, since correct range size is not known, we should at least warn that a range with invalid size was created so that user can amend it. https://fedorahosted.org/freeipa/ticket/2892 --- ipalib/constants.py | 2 ++ ipaserver/install/plugins/adtrust.py | 59 ++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/ipalib/constants.py b/ipalib/constants.py index ad6d188692aa3de70cf29d5662d84672054ab4ef..f0f89a3b3ff51e06709809d4d606af96d13a7063 100644 --- a/ipalib/constants.py +++ b/ipalib/constants.py @@ -105,6 +105,8 @@ DEFAULT_CONFIG = ( ('container_trusts', 'cn=trusts'), ('container_adtrusts', 'cn=ad,cn=trusts'), ('container_ranges', 'cn=ranges,cn=etc'), + ('container_dna', 'cn=dna,cn=ipa,cn=etc'), + ('container_dna_posix_ids', 'cn=posix-ids,cn=dna,cn=ipa,cn=etc'), # Ports, hosts, and URIs: # FIXME: let's renamed xmlrpc_uri to rpc_xml_uri diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py index abd676a2bcbec57f59eb6710560281d945cf0cea..78c1fc10bd5028b3f861478ab1493d2d73c3cc56 100644 --- a/ipaserver/install/plugins/adtrust.py +++ b/ipaserver/install/plugins/adtrust.py @@ -23,6 +23,8 @@ from ipalib import api, errors from ipalib.dn import DN from ipapython.ipa_log_manager import * +DEFAULT_ID_RANGE_SIZE = 200000 + class update_default_range(PostUpdate): """ Create default ID range for upgraded servers. @@ -46,18 +48,19 @@ class update_default_range(PostUpdate): try: (dn, admins_entry) = ldap.get_entry(dn, ['gidnumber']) except errors.NotFound: - root_logger.error("No local ID range and no admins group found. " - "Cannot create default ID range") + root_logger.error("default_range: No local ID range and no admins " + "group found. Cannot create default ID range") return (False, False, []) - base_id = admins_entry['gidnumber'][0] - id_range_size = 200000 + id_range_base_id = admins_entry['gidnumber'][0] + id_range_name = '%s_id_range' % api.env.realm + id_range_size = DEFAULT_ID_RANGE_SIZE range_entry = ['objectclass:top', 'objectclass:ipaIDrange', 'objectclass:ipaDomainIDRange', - 'cn:%s_id_range' % api.env.realm, - 'ipabaseid:%s' % base_id, + 'cn:%s' % id_range_name, + 'ipabaseid:%s' % id_range_base_id, 'ipaidrangesize:%s' % id_range_size, ] @@ -69,6 +72,50 @@ class update_default_range(PostUpdate): range_entry = map(str, range_entry) updates[dn] = {'dn' : dn, 'default' : range_entry} + # Default range entry has a hard-coded range size to 200000 which is + # a default range size in ipa-server-install. This could cause issues + # if user did not use a default range, but rather defined an own, + # bigger range (option --idmax). + # We should make our best to check if this is the case and provide + # user with an information how to fix it. + dn = str(DN(api.env.container_dna_posix_ids, api.env.basedn)) + search_filter = "objectclass=dnaSharedConfig" + attrs = ['dnaHostname', 'dnaRemainingValues'] + try: + (entries, truncated) = ldap.find_entries(search_filter, attrs, dn) + except errors.NotFound: + root_logger.warning("default_range: no dnaSharedConfig object found. " + "Cannot check default range size.") + else: + masters = set() + remaining_values_sum = 0 + for entry_dn, entry in entries: + hostname = entry.get('dnahostname', [None])[0] + if hostname is None or hostname in masters: + continue + remaining_values = entry.get('dnaremainingvalues', [''])[0] + try: + remaining_values = int(remaining_values) + except ValueError: + root_logger.warning("default_range: could not parse " + "remaining values from '%s'", remaining_values) + continue + else: + remaining_values_sum += remaining_values + + masters.add(hostname) + + if remaining_values_sum > DEFAULT_ID_RANGE_SIZE: + msg = ['could not verify default ID range size', + 'Please use the following command to set correct ID range size', + ' $ ipa range-mod %s --range-size=RANGE_SIZE"' % id_range_name, + 'RANGE_SIZE may be computed from --idstart and --idmax options ' + 'used during IPA server installation:', + ' RANGE_SIZE = (--idmax) - (--idstart) + 1' + ] + + root_logger.error("default_range: %s", "\n".join(msg)) + return (False, True, [updates]) api.register(update_default_range) -- 1.7.10.4
>From fb563a604fda390e0d2d9c22996d34a8440bbdfb Mon Sep 17 00:00:00 2001 From: Martin Kosek <mko...@redhat.com> Date: Wed, 11 Jul 2012 16:22:13 +0200 Subject: [PATCH 3/3] Print ipa-ldap-updater errors during RPM upgrade ipa-ldap-updater does a lot of essential LDAP changes and if it fails, user may be surprised after the upgrade why things does not work. Modify ipa-ldap-updater to print ERROR logging messages by default and modify RPM upgrade scriptlet to show these errors to user. https://fedorahosted.org/freeipa/ticket/2892 --- freeipa.spec.in | 2 +- install/tools/ipa-ldap-updater | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index deeb3341b9379a2cc82e50ca37889287c4c74813..7106310915c8a4e52a009036f7152a38a4c5f18d 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -465,7 +465,7 @@ fi %posttrans server # This must be run in posttrans so that updates from previous # execution that may no longer be shipped are not applied. -/usr/sbin/ipa-ldap-updater --upgrade >/dev/null 2>&1 || : +/usr/sbin/ipa-ldap-updater --upgrade >/dev/null || : %preun server if [ $1 = 0 ]; then diff --git a/install/tools/ipa-ldap-updater b/install/tools/ipa-ldap-updater index 197b840b07867269340f56e32989820d8af59ae1..e93cccd9679287fe5202d1071d3ee53f0ad22823 100755 --- a/install/tools/ipa-ldap-updater +++ b/install/tools/ipa-ldap-updater @@ -116,9 +116,9 @@ def main(): sys.exit("\nDirectory Manager password required") if options.upgrade: - standard_logging_setup('/var/log/ipaupgrade.log', verbose=True, debug=options.debug, filemode='a') + standard_logging_setup('/var/log/ipaupgrade.log', debug=options.debug, filemode='a') else: - standard_logging_setup(None, verbose=True, debug=options.debug) + standard_logging_setup(None, debug=options.debug) cfg = dict ( in_server=True, -- 1.7.10.4
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel