An old way to a new way - lib389 cheatsheet¶
Historically, lib389 had two object-oriented approaches on top of python-ldap. They help to get rid of a boilerplate code that we are end up with while working with different parts of 389-ds-base server. While using the original API we found out what we are missing and what can be improved, so we has started developing a new approach.
A cornerstone object of the new API is DSLdapObjects. It can be found in lib389/_mapped_object.py module. It represents the idea of a group of entries united by one purpose (i.e. users, groups, agreements, etc.) The entries are united by common ObjectClasses, must attributes and the rdn attribute. Also, it has a child - DSLdapObject, it represents a single ldap entry.
Examples¶
Users¶
The same way works for groups (but you have ou=groups instead of ou=people)
A python-ldap direct way:
dn = 'uid=test_user_1,ou=people,%s' % DEFAULT_SUFFIX
rdn = b'test_user_1'
attrs = {'objectclass': [b'top', b'person', b'organizationalPerson', b'inetOrgPerson'],
'uid': [rdn],
'sn' : [rdn],
'cn' : [rdn],
'description': b'a new entry'}
ldif = modlist.addModlist(attrs)
# Add a user
server.add_s(dn, ldif)
# Modify the user
server.modify_s(dn, [(ldap.MOD_DELETE, 'description', b'a new entry'),
(ldap.MOD_ADD, 'description', b'a modified entry')])
A new DSLdapObjects way:
from lib389.idm.user import UserAccounts
# Define all users under 'ou=people,%s' % DEFAULT_SUFFIX
users = UserAccounts(server, DEFAULT_SUFFIX)
# Add a simple user for the case when we don't care about exact attributes
user = users.create_test_user(uid=1000, gid=2000) # both attributes have default values so specifying them is optional
# Add a user with the exact attributes
# (objectclasses are taken from DSLdapObject definition but you can add some more)
user = users.create(properties={'uid': 'test_user_1',
'cn': 'test_user_1',
'sn': 'test_user_1',
'uidNumber': 1000,
'gidNumber': 2000,
'homeDirectory': '/home/test_user_1',
'description': 'a new entry'})
# Then we can work with the user entry
user.remove('description', 'a new entry')
user.add('description', 'a new entry')
description_attr_value = user.get_attr_val_utf8('description')
# You can search the users
users.list() # a list of DSLdapObject
# or get the user
user = users.get('test_user_1')
Agreements and pausing replication¶
An old lib389 object which is outdated:
M1 = topology_m4.ms['master1']
M2 = topology_m4.ms['master2']
M3 = topology_m4.ms['master3']
agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
M1.agreement.pause(agreement_m1_m2[0].dn)
M1.agreement.pause(agreement_m1_m3[0].dn)
M2.agreement.pause(agreement_m2_m1[0].dn)
M2.agreement.pause(agreement_m2_m3[0].dn)
DSLdapObjects Agreements which is currently fully supported and all the fixes go there:
from lib389.agreement import Agreements
agmts = Agreements(M1)
agmt = agmts.list()[0]
agmt.replace('nsDS5ReplicaCredentials', 'Secret123')
But if you want to pause/resume replication, it is easier to use other method:
from lib389.replica import ReplicationManager
repl = ReplicationManager(DEFAULT_SUFFIX)
# Pause/resume one replica direction
repl.disable_to_master(to_instance=M3, from_instances=[M1, M2])
repl.enable_to_master(to_instance=M3, from_instances=[M1, M2])
# Pause/resume all replication in the topology
topology_m4.pause_all_replicas()
topology_m4.resume_all_replicas()