diff options
author | Martin Kosek <mkosek@redhat.com> | 2011-10-03 16:01:01 +0200 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2011-10-11 23:24:00 -0400 |
commit | 2aa63fe4a98f6bae755b4ede607adc2068103c42 (patch) | |
tree | 7f107f01212aeb89c4ae409ae94d8f479288d87b | |
parent | 97fc2ed0ef401f2352e43f065d0bdf76f5c7521e (diff) | |
download | freeipa-2aa63fe4a98f6bae755b4ede607adc2068103c42.tar.gz freeipa-2aa63fe4a98f6bae755b4ede607adc2068103c42.tar.xz freeipa-2aa63fe4a98f6bae755b4ede607adc2068103c42.zip |
Improve handling of GIDs when migrating groups
Since IPA v2 server already contain predefined groups that may collide
with groups in migrated (IPA v1) server (for example admins, ipausers),
users having colliding group as their primary group may happen to belong
to an unknown group on new IPA v2 server.
Implement --group-overwrite-gid option to overwrite GID of already
existing groups to prevent this issue.
https://fedorahosted.org/freeipa/ticket/1866
-rw-r--r-- | API.txt | 7 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | ipalib/plugins/migration.py | 73 |
3 files changed, 67 insertions, 15 deletions
@@ -1701,9 +1701,9 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user") command: migrate_ds -args: 2,13,3 +args: 2,14,3 arg: Str('ldapuri', validate_ldapuri, cli_name='ldap_uri', label=Gettext('LDAP URI', domain='ipa', localedir=None)) -arg: Password('bindpw', cli_name='password', label=Gettext('Password', domain='ipa', localedir=None)) +arg: Password('bindpw', cli_name='password', confirm=False, label=Gettext('Password', domain='ipa', localedir=None)) option: Str('binddn?', autofill=True, cli_name='bind_dn', default=u'cn=directory manager', label=Gettext('Bind DN', domain='ipa', localedir=None)) option: Str('usercontainer?', autofill=True, cli_name='user_container', default=u'ou=people', label=Gettext('User container', domain='ipa', localedir=None)) option: Str('groupcontainer?', autofill=True, cli_name='group_container', default=u'ou=groups', label=Gettext('Group container', domain='ipa', localedir=None)) @@ -1713,8 +1713,9 @@ option: List('userignoreobjectclass?', autofill=True, cli_name='user_ignore_obje option: List('userignoreattribute?', autofill=True, cli_name='user_ignore_attribute', default=(), label=Gettext('Ignore user attribute', domain='ipa', localedir=None), multivalue=True) option: List('groupignoreobjectclass?', autofill=True, cli_name='group_ignore_objectclass', default=(), label=Gettext('Ignore group object class', domain='ipa', localedir=None), multivalue=True) option: List('groupignoreattribute?', autofill=True, cli_name='group_ignore_attribute', default=(), label=Gettext('Ignore group attribute', domain='ipa', localedir=None), multivalue=True) +option: Flag('groupoverwritegid', autofill=True, cli_name='group_overwrite_gid', default=False, label=Gettext('Overwrite GID', domain='ipa', localedir=None)) option: StrEnum('schema?', autofill=True, cli_name='schema', default=u'RFC2307bis', label=Gettext('LDAP schema', domain='ipa', localedir=None), values=(u'RFC2307bis', u'RFC2307')) -option: Flag('continue?', autofill=True, default=False) +option: Flag('continue?', autofill=True, default=False, label=Gettext('Continue', domain='ipa', localedir=None)) option: List('exclude_groups?', autofill=True, cli_name='exclude_groups', default=(), multivalue=True) option: List('exclude_users?', autofill=True, cli_name='exclude_users', default=(), multivalue=True) output: Output('result', <type 'dict'>, Gettext('Lists of objects migrated; categorized by type.', domain='ipa', localedir=None)) @@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=12 +IPA_API_VERSION_MINOR=13 diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py index 93ac114d8..852cc9d64 100644 --- a/ipalib/plugins/migration.py +++ b/ipalib/plugins/migration.py @@ -71,6 +71,15 @@ EXAMPLES: Specify the user and group container. This can be used to migrate user and group data from an IPA v1 server: ipa migrate-ds --user-container='cn=users,cn=accounts' --group-container='cn=groups,cn=accounts' ldap://ds.example.com:389 + + Since IPA v2 server already contain predefined groups that may collide with + groups in migrated (IPA v1) server (for example admins, ipausers), users having + colliding group as their primary group may happen to belong to an unknown group + on new IPA v2 server. + Use --group-overwrite-gid option to overwrite GID of already existing groups + to prevent this issue: + ipa migrate-ds --group-overwrite-gid --user-container='cn=users,cn=accounts' --group-container='cn=groups,cn=accounts' ldap://ds.example.com:389 + """) # USER MIGRATION CALLBACKS AND VARS @@ -228,6 +237,28 @@ def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwarg return dn +def _group_exc_callback(ldap, dn, entry_attrs, exc, options): + if isinstance(exc, errors.DuplicateEntry): + if options.get('groupoverwritegid', False) and \ + entry_attrs.get('gidnumber') is not None: + try: + new_entry_attrs = {'gidnumber':entry_attrs['gidnumber']} + ldap.update_entry(dn, new_entry_attrs) + except errors.EmptyModlist: + # no change to the GID + pass + # mark as success + return + elif not options.get('groupoverwritegid', False) and \ + entry_attrs.get('gidnumber') is not None: + msg = unicode(exc) + # add information about possibility to overwrite GID + msg = msg + unicode(_('. Check GID of the existing group. ' \ + 'Use --group-overwrite-gid option to overwrite the GID')) + raise errors.DuplicateEntry(message=msg) + + raise exc + # DS MIGRATION PLUGIN def construct_filter(template, oc_list): @@ -252,6 +283,7 @@ class migrate_ds(Command): # pre_callback - is called for each object just after it was # retrieved from DS and before being added to IPA # post_callback - is called for each object after it was added to IPA + # exc_callback - is called when adding entry to IPA raises an exception # # {pre, post}_callback parameters: # ldap - ldap2 instance connected to IPA @@ -270,7 +302,8 @@ class migrate_ds(Command): 'oc_blacklist_option' : 'userignoreobjectclass', 'attr_blacklist_option' : 'userignoreattribute', 'pre_callback' : _pre_migrate_user, - 'post_callback' : _post_migrate_user + 'post_callback' : _post_migrate_user, + 'exc_callback' : None }, 'group': { 'filter_template' : '(&(|%s)(cn=*))', @@ -278,7 +311,8 @@ class migrate_ds(Command): 'oc_blacklist_option' : 'groupignoreobjectclass', 'attr_blacklist_option' : 'groupignoreattribute', 'pre_callback' : _pre_migrate_group, - 'post_callback' : None + 'post_callback' : None, + 'exc_callback' : _group_exc_callback, }, } migrate_order = ('user', 'group') @@ -292,6 +326,7 @@ class migrate_ds(Command): Password('bindpw', cli_name='password', label=_('Password'), + confirm=False, doc=_('bind password'), ), ) @@ -359,6 +394,12 @@ class migrate_ds(Command): default=tuple(), autofill=True, ), + Flag('groupoverwritegid', + cli_name='group_overwrite_gid', + label=_('Overwrite GID'), + doc=_('When migrating a group already existing in IPA domain overwrite the '\ + 'group GID and report as success'), + ), StrEnum('schema?', cli_name='schema', label=_('LDAP schema'), @@ -368,6 +409,7 @@ class migrate_ds(Command): autofill=True, ), Flag('continue?', + label=_('Continue'), doc=_('Continuous operation mode. Errors are reported but the process continues'), default=False, ), @@ -539,16 +581,25 @@ can use their Kerberos accounts.''') try: ldap.add_entry(dn, entry_attrs) except errors.ExecutionError, e: - failed[ldap_obj_name][pkey] = unicode(e) - else: - migrated[ldap_obj_name].append(pkey) - - callback = self.migrate_objects[ldap_obj_name]['post_callback'] + callback = self.migrate_objects[ldap_obj_name]['exc_callback'] if callable(callback): - callback( - ldap, pkey, dn, entry_attrs, failed[ldap_obj_name], - config, context - ) + try: + callback(ldap, dn, entry_attrs, e, options) + except errors.ExecutionError, e: + failed[ldap_obj_name][pkey] = unicode(e) + continue + else: + failed[ldap_obj_name][pkey] = unicode(e) + continue + + migrated[ldap_obj_name].append(pkey) + + callback = self.migrate_objects[ldap_obj_name]['post_callback'] + if callable(callback): + callback( + ldap, pkey, dn, entry_attrs, failed[ldap_obj_name], + config, context, + ) return (migrated, failed) |