From 55c62ac79af235b75f969434aba775c4a8c30274 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 4 Nov 2009 15:56:43 -0500 Subject: Add support for setting/adding arbitrary attributes This introduces 2 new params: --setattr and --addattr Both take a name/value pair, ala: ipa user-mod --setattr=postalcode=20601 jsmith --setattr replaces or sets the current attribute to the value --addattr adds the value to an attribute (or sets a new attribute) OptionsParser allows multiple versions of this, so you can have multiple setattr and addattr, either for the same attribute or for different attributes. ipa user-mod --addattr=postalcode=20601 --addattr=postalcode=30330 jsmith Values are silent dropped if either of these on an existing param: ipa user-mod --setattr=givenname=Jerry jsmith Is a no-op. --- ipalib/plugins/baseldap.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'ipalib/plugins/baseldap.py') diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index 3798d838..b0ea5738 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -20,6 +20,7 @@ Base classes for LDAP plugins. """ +import re from ipalib import crud, errors, uuid from ipalib import Command, Method, Object from ipalib import Flag, List, Str @@ -27,6 +28,28 @@ from ipalib.base import NameSpace from ipalib.cli import to_cli, from_cli +def validate_add_attribute(ugettext, attr): + validate_attribute(ugettext, 'addattr', attr) + +def validate_set_attribute(ugettext, attr): + validate_attribute(ugettext, 'setattr', attr) + +def validate_attribute(ugettext, name, attr): + m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", attr) + if not m or len(m.groups()) != 2: + raise errors.ValidationError(name=name, error='Invalid format. Should be name=value') + +def get_attributes(attrs): + """ + Given a list of values in the form name=value, return a list of name. + """ + attrlist=[] + for attr in attrs: + m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", attr) + attrlist.append(str(m.group(1)).lower()) + + return attrlist + class LDAPObject(Object): """ Object representing a LDAP entry. @@ -111,6 +134,16 @@ class LDAPCreate(crud.Create): doc='print entries as they are stored in LDAP', exclude='webui', ), + Str('addattr*', validate_add_attribute, + cli_name='addattr', + doc='Add an attribute/value pair. Format is attr=value', + exclude='webui', + ), + Str('setattr*', validate_set_attribute, + cli_name='setattr', + doc='Set an attribute to an name/value pair. Format is attr=value', + exclude='webui', + ), ) def get_args(self): @@ -241,6 +274,16 @@ class LDAPUpdate(LDAPQuery, crud.Update): cli_name='all', doc='retrieve all attributes', ), + Str('addattr*', validate_add_attribute, + cli_name='addattr', + doc='Add an attribute/value pair. Format is attr=value', + exclude='webui', + ), + Str('setattr*', validate_set_attribute, + cli_name='setattr', + doc='Set an attribute to an name/value pair. Format is attr=value', + exclude='webui', + ), ) def execute(self, *keys, **options): @@ -257,6 +300,24 @@ class LDAPUpdate(LDAPQuery, crud.Update): dn = self.pre_callback(ldap, dn, entry_attrs, attrs_list, *keys, **options) + """ + Some special handling is needed because we need to update the + values here rather than letting ldap.update_entry() do the work. We + have to do the work of adding new values to an existing attribute + because if we pass just what is addded only the new values get + set. + """ + if 'addattr' in options: + (dn, old_entry) = ldap.get_entry(dn, attrs_list) + attrlist = get_attributes(options['addattr']) + for attr in attrlist: + if attr in old_entry: + if type(entry_attrs[attr]) in (tuple,list): + entry_attrs[attr] = old_entry[attr] + entry_attrs[attr] + else: + old_entry[attr].append(entry_attrs[attr]) + entry_attrs[attr] = old_entry[attr] + try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: -- cgit