Table of Contents
Identity Manager and Converting Multi-Valued Attributes to Single-Valued Attributes
This is an article on how to combine multiple values from a multi-valued attribute into a single valued attribute. This is required when you have multiple values in for example the Location or Room Number in eDirectory.
Symptom
We are first going to see what goes wrong:
One value
When we populate the location field in iManager for a synchronized user the value gets synced as well: Enter the single value in iManager:
And the value get synced to Active Directory:
Two values
Now we first remove the original value (make sure the removal of the attribute gets synchronized) and then add two values to the attribute:
But the value doesn't sync through:
But in the dstrace log we see an error:
13:07:48 AD-driver ST: DirXML Log Event ------------------- Driver: \SHIFT-TREE\shift\AD-driver\AD-driver Channel: Subscriber Object: \SHIFT-TREE\shift\SHIFTUSERS\SjoerdH Status: Error Message: <ldap-err ldap-rc="20" ldap-rc-name="LDAP_ATTRIBUTE_OR_VALUE_EXISTS"> <client-err ldap-rc="20" ldap-rc-name="LDAP_ATTRIBUTE_OR_VALUE_EXISTS">Attribute Or Value Exists</client-err> <server-err>00002081: AtrErr: DSID-030F10D6, #1: 0: 00002081: DSID-030F10D6, problem 1006 (ATT_OR_VALUE_EXISTS), data 0, Att 13 (physicalDeliveryOfficeName) </server-err> <server-err-ex win32-rc="8321"/> </ldap-err>
Solution
To solve this issue we need to create a new policy, and in that policy we have to create three rules:
- Setup Local Variable
- Concatenate Values
- Remove Values If Needed
First I'll show you each rule individually and after that the end result.
Create Policy
The policy has to be created in the “Event Transformation Policies”:
Click 'Insert' and provide the required values:
Setup Local Variable
We first create a simple rule that creates a local variable that is a nodeset of the L (location) attribute:
Concatenate Values
The second rule is a bit more complex. The conditions are still simple:
But the actions are a bit more complicated. Below I show you first the complete action list, and then I explain the first and third one a bit more in depth:
The first action is not even entirely visible. Click on the 'Edit the Actions' button. Now you see that 'for each' value you create a local variable called lvlocationoffice:
And again, this time the arguments, are not entirely visible. Click on the 'Edit the arguments'. Here you set the variable to itself, followed by a comma, a space, and a special value called 'current-node'. The current-node is the attribute value for the specific increment the loop is on:
The third actions needs a more in depth view of the arguments, if you click 'Edit the arguments' you can edit the verb 'Replace First'. Don't forget that you're replacing a comma and a space:
Remove Values If Needed
End Result
iManager view
XML
<?xml version="1.0" encoding="UTF-8"?><policy> <rule> <description>Setup Local variable</description> <conditions> <or> <if-op-attr name="L" op="available"/> <if-op-attr name="L" op="changing"/> </or> </conditions> <actions> <do-set-local-variable name="locationoffice"> <arg-node-set> <token-src-attr name="L"/> </arg-node-set> </do-set-local-variable> </actions> </rule> <rule> <description>Concatenate Values</description> <conditions> <and> <if-local-variable name="locationoffice" op="available"/> <if-src-attr name="L" op="available"/> </and> </conditions> <actions> <do-for-each> <arg-node-set> <token-local-variable name="locationoffice"/> </arg-node-set> <arg-actions> <do-set-local-variable name="lvlocationoffice"> <arg-string> <token-local-variable name="lvlocationoffice"/> <token-text xml:space="preserve">, </token-text> <token-local-variable name="current-node"/> </arg-string> </do-set-local-variable> </arg-actions> </do-for-each> <do-strip-op-attr name="L"/> <do-set-dest-attr-value class-name="User" name="L"> <arg-value type="string"> <token-replace-first regex=", " replace-with=""> <token-local-variable name="lvlocationoffice"/> </token-replace-first> </arg-value> </do-set-dest-attr-value> </actions> </rule> <rule> <description>Remove Values If Needed</description> <conditions> <and> <if-src-attr name="L" op="not-available"/> </and> </conditions> <actions> <do-strip-op-attr name="L"/> <do-clear-dest-attr-value name="L"/> </actions> </rule> </policy>
Test
Now the values in eDirectory give these values in Active Directory:
But also, these values sync back:
Sources
Cool Solution: Multi-valued Attribute to a Single-valued String
http://www.novell.com/support/dynamickc.do?cmd=show&forward=nonthreadedKC&docType=kc&externalId=10097756&sliceId=
http://www.novell.com/communities/node/3075/synchronizing-single-and-multi-valued-attributes-adedirectory
http://www.novell.com/communities/node/9413/generic-single-valued-schema-enforcement