Replica

Usage example

Basically, when you want a simple replica configuration without any hubs, you can use create_topology function. In more complex cases you have to use our Replica API to build your own topology exactly the way you want it. Still, it is better if you’ll use the ‘create_topology’ method for basic initial setup and then you can continue to expand it.

from lib389.topologies import create_topology

topology = create_topology({ReplicaRole.MASTER: 2,
                            ReplicaRole.CONSUMER: 2})

For basic Replica operations (the rest in the docs bellow):

from lib389.replica import Replicas

replicas = Replicas(standalone)
# Enable replication
# - changelog will be created
# - replica manager will be with the defaults
# - replica.create() will be executed
replica = replicas.enable(suffix=DEFAULT_SUFFIX,
                          role=ReplicaRole.MASTER,
                          replicaID=REPLICAID_MASTER_1)

# Or you can get it as usual DSLdapObject
replica = replicas.list()[0]

# Roles - ReplicaRole.MASTER, ReplicaRole.HUB, and ReplicaRole.CONSUMER
# For masters and hubs you can use the constants REPLICAID_MASTER_X and REPLICAID_HUB_X
# Change X for a number from 1 to 100 - for role ReplicaRole.MASTER only

# Disable replication
# - agreements and replica entry will be deleted
# - changelog is not deleted (but should?)
replicas.disable(suffix=DEFAULT_SUFFIX)

# Get RUV entry
replicas.get_ruv_entry()

# Get DN
replicas.get_dn(suffix)

# Promote
replicas.promote(suffix=DEFAULT_SUFFIX,
                 newrole=ReplicaRole.MASTER,
                 binddn=REPL_BINDDN,
                 rid=REPLICAID_MASTER_1)
# Demote
replicas.demote(suffix=DEFAULT_SUFFIX,
                newrole=ReplicaRole.CONSUMER)
# Test, that replication works
replicas.test(master2)

# Additional replica object methods
# Get role
replica.get_role()

replica.deleteAgreements()

Module documentation

class lib389.replica.ReplicationManager(suffix, logger=None)[source]

The lib389 replication manager. This is used to coordinate replicas and agreements between servers.

Unlike the raw replicas / agreement types that manipulate the servers configuration, this is a “high level” coordination type. It’s capable of taking multiple instances and joining them. It consumes many lib389 types like Replicas, Agreements and more.

It is capable of creating the first master in a topoolgy, joining masters and consumers to that topology, populating per-server replication credentials, dynamic rid allocation, and more.

Unlike hand management of agreements, this is able to take simpler steps to agreement creation. For example:

repl = ReplicationManager(<suffix>) repl.create_first_master(master1) repl.join_master(master1, master2)

Contrast to previous implementations of replication which required much more knowledge and parameters, this is able to securely add masters.

Parameters
  • suffix (str) – The suffix to replicate.

  • logger (python logging) – A logging interface

create_first_master(instance)[source]

In a topology, this creates the “first” master that has the database and content. A number of bootstrap tasks are performed on this master, as well as creating it’s replica type.

Once the first master is created, all other masters can be joined to it via “join_master”.

Parameters

instance (lib389.DirSrv) – An instance

disable_to_master(to_instance, from_instances=[])[source]

For all masters “from” disable all agreements “to” instance.

Parameters
  • to_instance (lib389.DirSrv) – The instance to stop recieving data.

  • from_instances (list[lib389.DirSrv]) – The instances to stop sending data.

enable_to_master(to_instance, from_instances=[])[source]

For all masters “from” enable all agreements “to” instance.

Parameters
  • to_instance (lib389.DirSrv) – The instance to start recieving data.

  • from_instances (list[lib389.DirSrv]) – The instances to start sending data.

ensure_agreement(from_instance, to_instance, init=False)[source]

Guarantee that a replication agreement exists ‘from_instance’ send data ‘to_instance’. This can be for any instance, master, hub, or consumer.

Both instances must have been added to the topology with create first master, join_master, join_consumer or join_hub.

Parameters
  • from_instance (lib389.DirSrv) – An instance already in the topology.

  • to_instance (lib389.DirSrv) – An instance to replicate to.

get_rid(instance)[source]

For a given master, retrieve it’s RID for this suffix.

Parameters

instance (lib389.DirSrv) – The instance

Returns

str

join_consumer(from_instance, to_instance)[source]

Join a new consumer to this instance. This will complete a total init of the data “from instance” to “to instance”.

This can be conducted from any master or hub in the topology as “from” master.

Parameters
  • from_instance (lib389.DirSrv) – An instance already in the topology.

  • to_instance (lib389.DirSrv) – An instance to join to the topology.

join_hub(from_instance, to_instance)[source]

Join a new hub to this instance. This will complete a total init of the data “from instance” to “to instance”.

This can be conducted from any master or hub in the topology as “from” master.

Not implement yet.

Parameters
  • from_instance (lib389.DirSrv) – An instance already in the topology.

  • to_instance (lib389.DirSrv) – An instance to join to the topology.

join_master(from_instance, to_instance)[source]

Join a new master in MMR to this instance. This will complete a total init of the data “from instance” to “to instance”.

This can be conducted from any master in the topology as “from” master.

Parameters
  • from_instance (lib389.DirSrv) – An instance already in the topology.

  • to_instance (lib389.DirSrv) – An instance to join to the topology.

remove_master(instance, remaining_instances=[], purge_sa=True)[source]

Remove an instance from the replication topology.

If purge service accounts is true, remove the instances service account.

The purge_sa must be conducted on a remaining master to guarantee the result.

We recommend remaining instances contains all masters that have an agreement to instance, to ensure no dangling agreements exist. Masters with no agreement are skipped.

Parameters
  • instance – An instance to remove from the topology.

  • remaining_instances (list[lib389.DirSrv]) – The remaining masters of the topology.

  • purge_sa (bool) – Purge the service account for instance

test_replication(from_instance, to_instance, timeout=20)[source]

Wait for a replication event to occur from instance to instance. This shows some point of synchronisation has occured.

Parameters
  • from_instance (lib389.DirSrv) – The instance whos state we we want to check from

  • to_instance (lib389.DirSrv) – The instance whos state we want to check matches from.

  • timeout (int) – Fail after timeout seconds.

test_replication_topology(instances, timeout=20)[source]

Confirm replication works between all permutations of masters in the topology.

Parameters
  • instances (list[lib389.DirSrv]) – The masters.

  • timeout (int) – Fail after timeout seconds.

wait_for_replication(from_instance, to_instance, timeout=20)[source]

Wait for a replication event to occur from instance to instance. This shows some point of synchronisation has occured.

Parameters
  • from_instance (lib389.DirSrv) – The instance whos state we we want to check from

  • to_instance (lib389.DirSrv) – The instance whos state we want to check matches from.

  • timeout (int) – Fail after timeout seconds.

wait_for_ruv(from_instance, to_instance, timeout=20)[source]

Wait for the in-memory ruv ‘from_instance’ to be advanced past on ‘to_instance’. Note this does not mean the ruvs are “exact matches” only that some set of CSN states has been advanced past. Topics like fractional replication may or may not interfer in this process.

In essence this is a rough check that to_instance is at least at the replication state of from_instance. You should consider using wait_for_replication instead for a guarantee.

Parameters
  • from_instance (lib389.DirSrv) – The instance whos state we we want to check from

  • to_instance (lib389.DirSrv) – The instance whos state we want to check matches from.

class lib389.replica.RUV(ruvs=[], logger=None)[source]

Represents the server in memory RUV object. The RUV contains each update vector the server knows of, along with knowledge of CSN state of the replica we have sent data to.

Parameters
  • ruvs (list[str]) – A list of nsds50ruv values.

  • logger (logging object) – A logging interface.

alloc_rid()[source]

Based on the RUV, determine an available RID for the replication topology that is unique.

Returns

str

format_ruv()[source]

Parse RUV into human readable format

Returns

dict

is_synced(other_ruv)[source]

Compare two server ruvs to determine if they are synced. This does not mean that replication is in sync (due to things like fractional repl), but in some cases can show that “at least some known point” has been achieved in the replication process.

Parameters

other_ruv (RUV object) – The other ruv object

Returns

bool

static parse_csn(csn)[source]

Parse CSN into human readable format ‘1970-01-31 00:00:00’

Parameters

csn (str) – the CSN to format

Returns

str

class lib389.replica.Replicas(instance)[source]

Replica DSLdapObjects for all replicas

Parameters

instance (lib389.DirSrv) – A instance

create(rdn=None, properties=None)[source]

Create an object under base DN of our entry

Parameters
  • rdn (str) – RDN of the new entry

  • properties (dict) – Attributes for the new entry

Returns

DSLdapObject of the created entry

ensure_state(rdn=None, properties=None)[source]

Create an object under base DN of our entry, or assert it exists and update it’s properties.

Parameters
  • rdn (str) – RDN of the new entry

  • properties (dict) – Attributes for the new entry

Returns

DSLdapObject of the created entry

exists(selector=[], dn=None)[source]

Check if a child entry exists

Returns

True if it exists

get(selector=[], dn=None)[source]

Get a child entry (DSLdapObject, Replica, etc.) with dn or selector using a base DN and objectClasses of our object (DSLdapObjects, Replicas, etc.) After getting the replica, update the replica._suffix parameter.

Parameters
  • dn (str) – DN of wanted entry

  • selector – An additional filter to objectClasses, i.e. ‘backend_name’

Returns

A child entry

lint(spec: Union[str, None, Type[List]] = None) → Generator[Any, None, None][source]

Lint the objects returned by list method according to the spec.

lint_list(spec: Optional[str] = None) → Generator[Tuple[str, Callable], None, None][source]

Yield specs the objects returned by list method provide.

list(paged_search=None, paged_critical=True)[source]

Get a list of children entries (DSLdapObject, Replica, etc.) using a base DN and objectClasses of our object (DSLdapObjects, Replicas, etc.)

Parameters

paged_search – None for no paged search, or an int of page size to use.

Returns

A list of children entries

process_and_dump_changelog(replica_root, output_file, csn_only=False, preserve_ldif_done=False, decode=False)[source]

Dump and decode Directory Server replication changelog

Parameters
  • replica_root (str) – Replica suffix that needs to be processed

  • output_file – The file name for the exported changelog LDIF file

  • csn_only (bool) – Grep only the CSNs from the file

  • preserve_ldif_done (bool) – Preserve the result LDIF and rename it to [old_name].done

  • decode – Decode any base64 values from the changelog

restore_changelog(replica_root, log=None)[source]

Restore Directory Server replication changelog from ‘.ldif’ or ‘.ldif.done’ file

Parameters
  • replica_roots (list of str) – Replica suffixes that need to be processed (and optional LDIF file path)

  • log (logger) – The logger object

class lib389.replica.Replica(instance, dn=None)[source]

Replica DSLdapObject with: - must attributes = [‘cn’, ‘nsDS5ReplicaType’, ‘nsDS5ReplicaRoot’,

‘nsDS5ReplicaBindDN’, ‘nsDS5ReplicaId’]

  • RDN attribute is ‘cn’

  • There is one “replica” per backend

Parameters
  • instance (lib389.DirSrv) – A instance

  • dn (str) – Entry DN

add(key, value)[source]

Add an attribute with a value

Parameters
  • key (str) – an attribute name

  • value (str) – an attribute value

apply_mods(mods)[source]

Perform modification operation using several mods at once

Parameters

mods (list of tuples) – [(action, key, value),] or [(ldap.MOD_DELETE, key),]

Raises

ValueError - if a provided mod op is invalid

begin_task_cl2ldif()[source]

Begin the changelog to ldif task

begin_task_ldif2cl()[source]

Begin ldif to changelog task

cleanRUV(rid)[source]

Run a cleanallruv task, only on a master, after deleting or demoting it. It is okay if it fails.

classmethod compare(obj1, obj2)[source]

Compare if two RDN objects have same attributes and values.

This comparison is a loose comparison, not a strict one i.e. “this object is this other object” It will just check if the attributes are same. ‘nsUniqueId’ attribute is not checked intentionally because we want to compare arbitrary objects i.e they may have different ‘nsUniqueId’ but same attributes.

Example:

cn=user1,ou=a
cn=user1,ou=b

Comparision of these two objects should result in same, even though their ‘nsUniqueId’ attribute differs.

Parameters
  • obj1 (lib389._mapped_object.DSLdapObject) – An entry to check

  • obj2 (lib389._mapped_object.DSLdapObject) – An entry to check

Returns

True if objects have same attributes else returns False

Raises

ValueError - if obj1 or obj2 don’t inherit DSLdapObject

create(rdn=None, properties=None, basedn=None)[source]

Add a new entry

Parameters
  • rdn (str) – RDN of the new entry

  • properties (dict) – Attributes for the new entry

  • basedn – Base DN of the new entry

Returns

DSLdapObject of the created entry

delete()[source]

Delete a replica related to the provided suffix.

If this replica role was ReplicaRole.HUB or ReplicaRole.MASTER, it also deletes the changelog associated to that replica. If it exists some replication agreement below that replica, they are deleted. If this is a master we also clean the database ruv.

Returns

None

Raises
  • InvalidArgumentError - if suffix is missing

  • ldap.LDAPError - for all other update failures

demote(newrole)[source]

Demote a replica to a hub or consumer

Parameters

newrole (ReplicaRole) – The new replication role for the replica: CONSUMER and HUB

Returns

None

Raises

ValueError - If replica is not demoted

display(attrlist=['*'])[source]

Get an entry but represent it as a string LDIF

Returns

LDIF formatted string

display_attr(attr)[source]

Get all values of given attribute - ‘attr: value’

Returns

Formatted string

property dn

Get an object DN

Returns

DN

ensure_attr_state(state)[source]

Given a dict of attr-values, ensure they are in the same state on the entry. This is a stateful assertion, generally used by things like PATCH in a REST api.

The format is:
{

‘attr_1’: [‘value’, ‘value’], ‘attr_2’: [],

}

If a value is present in the list, but not in the entry it is ADDED. If a value is NOT present in the list, and is on the entry, it is REMOVED. If a value is an empty list [], the attr is REMOVED from the entry. If an attr is not named in the dictionary, it is not altered.

This function is atomic - all changes are applied or none are. There are no partial updates.

This function is idempotent - submitting the same request twice will cause no action to be taken as we are ensuring a state, not listing actions to take.

Parameters

state (dict) – The entry ava state

ensure_present(attr, value)[source]

Ensure that an attribute and value are present in a state, or add it.

Parameters
  • key (str) – an attribute name

  • value (str) – an attribute value

ensure_removed(attr, value)[source]

Ensure that a attribute and value has been removed and not present or remove it.

Parameters
  • key (str) – an attribute name

  • value (str) – an attribute value

ensure_state(rdn=None, properties=None, basedn=None)[source]

Ensure an entry exists with the following state, created if necessary.

Parameters
  • rdn (str) – RDN of the new entry

  • properties (dict) – Attributes for the new entry

  • basedn – Base DN of the new entry

Returns

DSLdapObject of the created entry

exists()[source]

Check if the entry exists

Returns

True if it exists

get_agreements(winsync=False)[source]

Return the set of agreements related to this suffix replica :param: winsync: If True then return winsync replication agreements,

otherwise return teh standard replication agreements.

Returns

A list Replicas objects

get_all_attrs(use_json=False)[source]

Get a dictionary having all the attributes of the entry

Returns

Dict with real attributes and operational attributes

get_all_attrs_utf8(use_json=False)[source]

Get a dictionary having all the attributes of the entry

Returns

Dict with real attributes and operational attributes

get_attr_val_bytes(key, use_json=False)[source]

Get a single attribute value from the entry in bytes type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_val_int(key, use_json=False)[source]

Get a single attribute value from the entry in int type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_val_utf8(key, use_json=False)[source]

Get a single attribute value from the entry in utf8 type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_val_utf8_l(key, use_json=False)[source]

Get a single attribute value from the entry in utf8 type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_vals_bytes(key, use_json=False)[source]

Get attribute values from the entry in bytes type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_vals_int(key, use_json=False)[source]

Get attribute values from the entry in int type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_vals_utf8(key, use_json=False)[source]

Get attribute values from the entry in utf8 type

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_attr_vals_utf8_l(key, use_json=False)[source]

Get attribute values from the entry in utf8 type and lowercase

Parameters

key (str) – An attribute name

Returns

A single bytes value

Raises

ValueError - if instance is offline

get_basedn()[source]

Get the suffix this entry belongs to

get_compare_attrs(use_json=False)[source]

Get a dictionary having attributes to be compared i.e. excluding self._compare_exclude

get_consumer_replicas(get_credentials)[source]

Return the set of consumer replicas related to this suffix replica through its agreements

Parameters

get_credentials – A user-defined callback function which returns the binding credentials using given host and port data - {“binddn”: “cn=Directory Manager”, “bindpw”: “password”}

Returns

Replicas object

get_maxcsn()[source]

Return the current replica’s maxcsn for this suffix

Returns

str

get_rid()[source]

Return the current replicas RID for this suffix

Returns

str

get_role()[source]

Return the replica role

Returns

ReplicaRole.MASTER, ReplicaRole.HUB, ReplicaRole.CONSUMER

get_ruv()[source]

Return the in memory ruv of this replica suffix.

Returns

RUV object

Raises

LDAPError

get_ruv_agmt_maxcsns()[source]

Return the in memory ruv of this replica suffix.

Returns

RUV object

Raises

LDAPError

get_suffix()[source]

Return the suffix

get_tombstone_count()[source]

Get the number of tombstones

lint(spec: Union[str, None, Type[List]] = None) → Generator[Any, None, None][source]

Lint the object according to the spec.

lint_list(spec: Optional[str] = None) → Generator[Tuple[str, Callable], None, None][source]

Yield specs the object provides.

This yields from each lint method yielding all specs it can provide.

present(attr, value=None)[source]

Assert that some attr, or some attr / value exist on the entry.

Parameters
  • attr (str) – an attribute name

  • value (str) – an attribute value

Returns

True if attr is present

promote(newrole, binddn=None, binddn_group=None, rid=None)[source]

Promote the replica to hub or master

Parameters
  • newrole (ReplicaRole) – The new replication role for the replica: MASTER and HUB

  • binddn (str) – The replication bind dn - only applied to master

  • binddn_group – The replication bind dn group - only applied to master

  • rid (int) – The replication ID, applies only to promotions to “master”

Returns

None

Raises

ValueError - If replica is not promoted

property rdn

Get an object RDN

Returns

RDN

remove(key, value)[source]

Remove a value defined by key

Parameters
  • key (str) – an attribute name

  • value (str) – an attribute value

remove_all(key)[source]

Remove all values defined by key (if possible).

If an attribute is multi-valued AND required all values except one will be deleted.

Parameters

key (str) – an attribute name

rename(new_rdn, newsuperior=None, deloldrdn=True)[source]

Renames the object within the tree.

If you provide a newsuperior, this will move the object in the tree. If you only provide a new_rdn, it stays in the same branch, but just changes the rdn.

Note, if you use newsuperior, you may move this object outside of the scope of the related DSLdapObjects manager, which may cause it not to appear in .get() requests.

Parameters
  • new_rdn (str) – RDN of the new entry

  • newsuperior (str) – New parent DN

replace(key, value)[source]

Replace an attribute with a value

Parameters
  • key (str) – an attribute name

  • value (str) – an attribute value

replace_many(*args)[source]

Replace many key, value pairs in a single operation. This is useful for configuration changes that require atomic operation, and ease of use.

An example of usage is replace_many((key, value), (key, value))

No wrapping list is needed for the arguments.

Parameters

*args

tuples of key,value to replace.

set(key, value, action=2)[source]

Perform a specified action on a key with value

Parameters
  • key (str) – an attribute name

  • value (str) – an attribute value

  • action (int) –

    • ldap.MOD_REPLACE - by default

    • ldap.MOD_ADD

    • ldap.MOD_DELETE

Returns

result of modify_s operation

Raises

ValueError - if instance is not online

status(binddn=None, bindpw=None, winsync=False)[source]

Get a list of the status for every agreement

task_finished()[source]

Wait for a replica task to complete: CL2LDIF / LDIF2CL

test_replication(replica_dirsrvs)[source]

Make a “dummy” update on the the replicated suffix, and check all the provided replicas to see if they received the update.

Parameters

*replica_dirsrvs

DirSrv instance, DirSrv instance, …

Returns

True - if all servers have recevioed the update by this replica, otherwise return False

Raises

LDAPError - when failing to update/search database