You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 17 Next »

Introduction

This page describes the way we generate reverse LDIF, for each forward operation. A reverse LDIF can be applied on a server in order to revert an operation.

In this document we do not consider what is required to revert a series of operations which have ordering requirements: i.e. they must be applied in reverse order. Here we simply focus on how to generate the LDIF for each atomic operation.

Operations

Operations to generate reverse LDIF for:

Operation

AddRequest

DelRequest

ModifyRequest

ModifyDNRequest

AddRequest

Computing the reverse LDIF for an AddRequest is easy: it's a DelRequest where we use the DN of the created entry.

An AddRequest contains those informations :

AddRequest ::= [APPLICATION 8] SEQUENCE {
    entry           LDAPDN,
    attributes      AttributeList }

AttributeList ::= SEQUENCE OF attribute Attribute

For the added entry :

dn: cn=test, dc=example, dc=com
objectclass: top
objectclass: person
cn: test
sn: This is a test

the reverse LDIF will be :

dn: cn=test, dc=example, dc=com
changetype: delete

DelRequest

To produce a reverse LDIF for a DelRequest, we must first read the deleted attribute. We will create a AddRequest based on the read deleted entry :

* read the entry to be deleted
* create a revert ldif AddRequest with this deleted entry
* delete the entry

Considering the existing entry :

dn: cn=test, dc=example, dc=com
objectclass: top
objectclass: person
cn: test
sn: This is a testcreatorsName:  dc=admin, ou=systemcreateTimestamp: 20071010150132ZmodifiersName:  dc=admin, ou=systemmodifyTimestamp:  20071010150133Z

 if we have a delRequest which ldif is :

dn: cn=test, dc=example, dc=com
changetype: delete

 the reversed ldif should be :

dn: cn=test, dc=example, dc=comchangetype: add
objectclass: top
objectclass: person
cn: test
sn: This is a test

There is still a question regarding operational attributes: should we keep them (in the LDIF)? How do we guarantee that the creatorsName and createTimeStamp attributes are the original ones, instead of the one injected while creating the saved entry? Operational attribute state needs to be captured out of band (from the LDIF data) and is the responsibility of the change log service to manage, capture and track. This information is made available to higher level interfaces which handle all this. So at this level we need not worry: the LDIF's generated have no operational attributes in them as would be normally expected for a valid LDIF.

To be able to build this reverse ldif, we need to read the previous entry before the deletion.

ModifyRequest

This is the most complex operation. The modification is applied on a specific entry, and can impact one or more attribute, one or more value, but it can't modify an attribute which is part iof the entry RDN.

We have three kind of modifications : add, delete and replace. They are applied in the order they are found in the Modify request, so the reverse LDIF must store them in reverse order too.

Depending on the modified values, each basic operation may have some different semantic. The following table present all the possible actions :

modification

initial entry

imported Ldif

resulting entry

Comments

Reverse LDIF

add

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

dn: cn=test, ou=system
changetype: modify
add: ou
ou: BigCompany inc.
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp
ou: BigCompany inc.

In this case, the ou value is simply added

dn: cn=test, ou=system
changetype: modify
delete: ou
ou: BigCompany inc.
-

add

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

dn: cn=test, ou=system
changetype: modify
add: ou
ou: BigCompany inc.
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: BigCompany inc.

The ou attribute and its value has been created

dn: cn=test, ou=system
changetype: modify
delete: ou
ou: BigCompany inc.
-

add

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

dn: cn=test, ou=system
changetype: modify
add: cn
cn: test
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

Nothing is done.

no reverse, void operation

delete

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

dn: cn=test, ou=system
changetype: modify
delete: ou
ou: acme corp
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache

The ou=acme corp value has been deleted

dn: cn=test, ou=system
changetype: modify
add: ou
ou: acme corp
-

delete

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

dn: cn=test, ou=system
changetype: modify
delete: ou
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

The ou attribute has been removed

dn: cn=test, ou=system
changetype: modify
add: ou
ou: apache
ou: acme corp
-

delete

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

dn: cn=test, ou=system
changetype: modify
delete: ou
ou: apache
ou: acme corp
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

As all the ou values have been removed,
the attribute itself is deleted

dn: cn=test, ou=system
changetype: modify
add: ou
ou: apache
ou: acme corp
-

replace

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

dn: cn=test, ou=system
changetype: modify
replace: ou
ou: directory
ou: BigCompany inc.
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: directory
ou: BigCompany inc.

The ou attributes' values are replaced
by the new values.

dn: cn=test, ou=system
changetype: modify
replace: ou
ou: apache
ou: acme corp
-

replace

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

dn: cn=test, ou=system
changetype: modify
replace: ou
ou: apache
ou: acme corp
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

Create the ou attribute

dn: cn=test, ou=system
changetype: modify
replace: ou
-

replace

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA
ou: apache
ou: acme corp

dn: cn=test, ou=system
changetype: modify
replace: ou
-

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: joe doe
l: USA

Delete the ou attribute

dn: cn=test, ou=system
changetype: modify
replace: ou
ou: apache
ou: acme corp
-

ModifyDNRequest

This request is used to move entries or to rename entries or to move and rename entries. Its counterpart in a ldif file is a 'changetype: moddn' or a 'changetype: modrdn' operation (moddn or modrdn are synonymous).

There are five cases :

  1. we change the RDN, we don't change the superior and we don't delete the old RDN : This is a rename
  2. we change the RDN, we don't change the superior and we delete the old RDN : This is a rename, with cleaning
  3. we change the RDN, we change the superior and we don't delete the old RDN : This is a move and rename
  4. we change the RDN, we change the superior and we delete the old RDN : This is a move and rename, with cleaning
  5. we don't change the RDN, we change the superior : this is a Move operation

We have also a few extra cases for 1 to 4, depending on the RDN composition (ie, wether it's a simple RDN or a composite RDN)

a.1  The initial RDN is simple, so is the target RDN (oldRdn: A, newRdn: B)

a.2 The initial RDN is simple, and the target RDN is composite, but they have different values (oldRdn: A, newRdn: B+C)

a.3 The initial RDN is simple, and the target RDN is composite, but they have overlaping values (oldRdn: A, newRdn: A+B)

a.4 The initial RDN is composite, and the taret RDN is simple, but they have different values (oldRdn: A+B, newRdn: C)

a.5 The initial RDN is composite, and the taret RDN is simple, but they have overlaping values (oldRdn: A+B, newRdn: A)

a.6 Both RDN are composite, but don't overlap (oldRdn: A+B, newRdn: C+D)

a.7 Both RDN are composite, and they overlap (oldRdn: A+B, newRdn: B+C)

All those special cases applies to each of the rename operation. We can use this algorithjm to handle them :

- Create all the attributes which are present in the newRdn but not in the oldRdn

- Suppress all the attributes which are present in the oldRdn but not in the newRdn if the deleteOldRdn flag is true

To compute the revert operation, we do the opposite :

- remove all the attributes which are present in the newRdn but not in the oldRdn

- create all the attributes which are present in the oldRdn but not in the newRdn (if they are already present, it won't be a problem)

In any case, we don't have to take care of the deleteOldRdn flag to compute the revert operation.

  

The following table gives an example for each of those cases applied on the initial entry :

dn: cn=test, dc=example, dc=com
objectclass: top
objectclass: person
cn: test
sn: This is a test

For a.1, the new superior will be 'ou=system', the old RDN will be 'cn=test', the new RDN will be 'cn=joe'

For a.1, the new superior will be 'ou=system', the old RDN will be 'cn=test', the new RDN will be 'cn=joe+sn=the plumber'

case

deleteoldrdn

new superior

modifying ldif

resulting entry

reverse ldif

1

no

none

dn: cn=test, dc=example, dc=com
changetype: moddn
deleteoldrdn: 0
newrdn: cn=joe

dn: cn=joe, dc=example, dc=com
objectclass: top
objectclass: person
cn: test
cn: joe
sn: This is a test

dn: cn=joe, dc=example, dc=com
changetype: moddn
deleteoldrdn: 1
newrdn: cn=test 

1.2

no

none

dn: cn=test, dc=example, dc=com
changetype: moddn
deleteoldrdn: 0
newrdn: cn=joe

dn: cn=joe+sn=the plumber, dc=example, dc=com
objectclass: top
objectclass: person
cn: test
cn: joe
sn: This is a test
sn: the plumber

dn: cn=joe+sn=the plumber, dc=example, dc=com
changetyp: moddn
deleteoldrdn: 1
nexrdn: cn=test

2

yes

none

dn: cn=test, dc=example, dc=com
changetype: moddn
deleteoldrdn: 1
newrdn: cn=joe

dn: cn=joe, dc=example, dc=com
objectclass: top
objectclass: person
cn: test
cn: joe
sn: This is a test

dn: cn=joe, dc=example, dc=com
changetype: moddn
deleteoldrdn: 1
newrdn: cn=test  

3

no

ou=system

dn: cn=test, dc=example, dc=org
changetype: moddn
deleteoldrdn: 0
newrdn: cn=joe
newsuperior: ou=system

dn: cn=joe, ou=system
objectclass: top
objectclass: person
cn: test
cn: joe
sn: This is a test

dn: cn=joe, ou=system
changetype: moddn
deleteoldrdn: 1
newrdn: cn=test  
newsuperior: dc=example, dc=com

4

yes

ou=system

dn: cn=test, dc=example, dc=org
changetype: moddn
deleteoldrdn: 1
newrdn: cn=joe
newsuperior: ou=system

dn: cn=joe, ou=system
objectclass: top
objectclass: person
cn: test
cn: joe
sn: This is a test

dn: cn=joe, ou=system
changetype: moddn
deleteoldrdn: 1

newrdn: cn=test 
newsuperior: dc=example, dc=com

5

no

ou=system

dn: cn=test, dc=example, dc=org
changetype: moddn
newrdn: cn=test
newsuperior: ou=system

dn: cn=test, ou=system
objectclass: top
objectclass: person
cn: test
sn: This is a test

dn: cn=test, ou=system
changetype: moddn
newsuperior: dc=example, dc=com
newrdn: cn=test

Computing the reverse LDIF for a ModifyDN request follows the algorithm :

if the newRdn is different from the existing RDN

  then reverseLdif.deleteOldRdn = true
  else reverseLdif.deleteOldRdn = false
if modifyDn.newSuperior not empty 
  then reverseLdif.newSuperior = modifyDn.dn minus the modifyDN.dn.getRDN
reverseLdif.newRdn = modifyDn.dn.getRDN

  • No labels