summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-11-04 15:56:43 -0500
committerJason Gerard DeRose <jderose@redhat.com>2009-11-17 09:40:56 -0700
commit55c62ac79af235b75f969434aba775c4a8c30274 (patch)
tree381c3afe13d0045f932252e5fcf294ca2384b241 /ipalib
parent680bf7c54863452263b9cd324ede444fd438436d (diff)
downloadfreeipa-55c62ac79af235b75f969434aba775c4a8c30274.tar.gz
freeipa-55c62ac79af235b75f969434aba775c4a8c30274.tar.xz
freeipa-55c62ac79af235b75f969434aba775c4a8c30274.zip
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.
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/frontend.py45
-rw-r--r--ipalib/plugins/baseldap.py61
2 files changed, 106 insertions, 0 deletions
diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index b13ffed42..e257a0a25 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -473,6 +473,34 @@ class Command(HasParam):
kw = self.args_options_2_params(*args, **options)
return dict(self.__attributes_2_entry(kw))
+ def __convert_2_dict(self, attrs, append=True):
+ """
+ Convert a string in the form of name/value pairs into
+ a dictionary. The incoming attribute may be a string or
+ a list.
+
+ Any attribute found that is also a param is silently dropped.
+
+ append controls whether this returns a list of values or a single
+ value.
+ """
+ newdict = {}
+ if not type(attrs) in (list, tuple):
+ attrs = [attrs]
+ for a in attrs:
+ m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", a)
+ attr = str(m.group(1)).lower()
+ value = m.group(2)
+ if len(value) == 0:
+ # None means "delete this attribute"
+ value = None
+ if attr not in self.params:
+ if append and attr in newdict:
+ newdict[attr].append(value)
+ else:
+ newdict[attr] = [value]
+ return newdict
+
def __attributes_2_entry(self, kw):
for name in self.params:
if self.params[name].attribute and name in kw:
@@ -482,6 +510,23 @@ class Command(HasParam):
else:
yield (name, kw[name])
+ adddict = {}
+ if 'setattr' in kw:
+ adddict = self.__convert_2_dict(kw['setattr'], append=False)
+
+ if 'addattr' in kw:
+ adddict.update(self.__convert_2_dict(kw['addattr']))
+
+ for name in adddict:
+ value = adddict[name]
+ if isinstance(value, list):
+ if len(value) == 1:
+ yield (name, value[0])
+ else:
+ yield (name, [v for v in value])
+ else:
+ yield (name, value)
+
def params_2_args_options(self, **params):
"""
Split params into (args, options).
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 3798d8388..b0ea57380 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: