Syncrepl Client Callbacks¶
When a Syncrepl
instance wants to tell you about
something, it uses a callback.
The complete list of callbacks, their parameters, and what they mean is defined
in BaseCallback
.
Syncrepl
doesn’t care if your object uses instance
methods, class methods, or static methods, so long as your callback is able to
accept the parameters provided.
In addition to BaseCallback
,
LoggingCallback
is provided as a way to log
the callbacks being received.
Both BaseCallback
and
LoggingCallback
are described below.
BaseCallback¶
-
class
syncrepl_client.callbacks.
BaseCallback
[source]¶ BaseCallback
is a class containing all of the callbacks whichsyncrepl_client.Syncrepl
may call. It is implemented as a new-style class, with class methods (althoughSyncrepl
doesn’t care).This class exists for two reasons:
- It documents each callback, the parameters the callback receives, and what the callback means.
- It gives you a useful base class to sink unwanted callbacks. If you only care about certain callbacks, you can implement them in your class, and let all the other callbacks percolate up to this class, where they are received and ignored.
Another reason for using classes is because they can be stacked. For example, if you want to handle callbacks, but you also want them to be logged, you can have your callback class use
LoggingCallback
as a base class, and then set theLoggingCallback
‘sdest
attribute to the log sink (which could bestdout
, or another file handle).Note
If your class needs any kind of setup or initalization before it can receive callbacks, it is suggested that you implement your callbacks as instance methods, and then use normal class instantiation to do your preparation, before handing off the instance to
Syncrepl
‘s constructor.-
classmethod
bind_complete
(ldap, cursor)[source]¶ Called to mark a successful bind to the LDAP server.
Parameters: - ldap (ldap.LDAPObject) – The LDAP object.
- cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns: None - any returned value is ignored.
This callback is used to indicate a successful bind, and to give you one opportunity to interact with the LDAP server, before the connection is taken over by the syncrepl search.
For example, if you want to record the bind DN (which you might not know, if you are doing things like a SASL bind), or you want to retrieve the schema stored on the server, this is the time to do it!
This is the very first callback to be called. Once the callback completes, the syncrepl search will begin, and other callbacks will start coming in.
Note
Once the callback has completed, there is no guarantee that ldap will still be a valid reference.
Warning
If you start any asynchronous operations (which includes searches), those operations must be completed before this callback returns.
Warning
Please do not unbind ldap from the LDAP server!
Warning
Once the callback completes, this LDAP connection will be used for the syncrepl search. No other operations will be allowed! If you want to communicate with the LDAP server after this callback completes, you will need to set up a separate LDAP connection.
cursor provides access to the underlying database, as described in
DBInterface
. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!Warning
Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.
-
classmethod
refresh_done
(items, cursor)[source]¶ Called to mark the end of the refresh phase.
Parameters: - items (dict) – The items currently in the directory.
- cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns: None – any returned value is ignored.
When receiving this callback, you know that the refresh phase has completed, and your view of the directory is now consistent with the LDAP server (at least, the part of the directory which matches your search and your access).
items
is a dictionary (or, an object which behaves like a dictionary) where the keys are DNs and the values are dicts of attributes & their values. Every item initems
is present in the directory at the time this callback started.Note
items
is read-only. Any attempt to add, change, or delete and item will cause anAttributeError
to be raised.Warning
The content
items
is guaranteed to be consistent only inside this callback. Once this callback returns, any attempts to accessitems
again will result in undefined behavior.cursor provides access to the underlying database, as described in
DBInterface
. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!Warning
Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.
If you need to do any sort of synchronization with anyone else, this is the best time to do it. Once you return from this callback, the persist phase will begin. The first database commit will also take place.
Note
Once you return from this callback, it may be some time before you see anything happen (either another callback, or
syncrepl_client.Syncrepl.poll()
returning. That is because the first database commit is taking place, and there may be _many_ changes to commit!If you are operating in refresh-only mode, then as soon as this callback completes,
syncrepl_client.Syncrepl.poll()
will returnFalse
. It is then safe to callunbind()
.
-
classmethod
record_add
(dn, attrs, cursor)[source]¶ Called to indicate the addition of a new LDAP record.
Parameters: - dn (str) – The DN of the added record.
- attrs (Dict of lists of bytes) – The record’s attributes.
- cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns: None - any returned value is ignored.
Warning
attrs
is passed by reference. If you modify the dictionary—or its contents—in any way, you will pay for it later!This callback can happen in all modes, and in all phases, to indicate that an entry has been added to your view of the search results. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the addition may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, a new entry has just been added—or modified—such that it matches your search.
Attributes which are not present in the record will not present in attrs. Dict keys are attribute names, and dict values are arrays (to support multi-valued attributes).
Note
Just because the dict values are arrays, does not mean that all attributes are multi-valued. The LDAP client does not know which attributes are single- and which are multi-valued, so it assumes that all are multi-valued.
Also, all attribute values will come in as (in Python 2)
str
objects or (in Python 3)bytes
objects.To learn which attributes are single- or multi-valued, and to learn the type (or, in LDAP terms, the syntax) of an attribute, you need to look at the schema, possibly using
ldap.schema
.cursor provides access to the underlying database, as described in
DBInterface
. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!Warning
Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.
-
classmethod
record_delete
(dn, cursor)[source]¶ Called to indicate the deletion of an LDAP record.
Parameters: - dn (str) – The DN of the deleted record.
- cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns: None - any returned value is ignored.
This callback can happen in all modes, and in all phases, to indicate that an entry has been either been deleted, or that it no longer matches your search. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the deletion may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, the entry has just disappeared.
cursor provides access to the underlying database, as described in
DBInterface
. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!Warning
Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.
-
classmethod
record_rename
(old_dn, new_dn, cursor)[source]¶ Called to indicate a change in DN.
Parameters: - old_dn (str) – The old DN.
- new_dn (str) – The new DN.
- cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns: None - any returned value is ignored.
This callback happens when an entry’s DN changes.
This callback can happen in all modes, and in all phases, to indicate that an entry’s DN has been changed. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the change may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, the entry has just changed.
cursor provides access to the underlying database, as described in
DBInterface
. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!Warning
Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.
You should expect a call to
record_change()
shortly after this callback completes.
-
classmethod
record_change
(dn, old_attrs, new_attrs, cursor)[source]¶ Called to indicate a change in attributes.
Parameters: - dn (str) – The DN of the changed record.
- old_attrs (Dict of lists of bytes) – The old attributes.
- new_attrs (Dict of lists of bytes) – The new attributes.
- cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns: None - any returned value is ignored.
This callback happens when an entry has changed.
You are provided with the old attributes, and the new attributes. It is up to you to determine what the changes are (if you care).
Note
If you look back at
record_add()
, see the note about changing attrs, and how it will come back to bite you? Well, here’s where it comes back to bite you!Warning
new_attrs is passed by reference. If you modify the dictionary—or its contents—in any way; you will pay for it later!
This callback can happen in all modes, and in all phases, to indicate that an entry has been changed. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the change may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, the entry has just changed.
Note
Just because the dict values are arrays, does not mean that all attributes are multi-valued. The LDAP client does not know which attributes are single- and which are multi-valued, so it assumes that all are multi-valued.
Also, all attribute values will come in as (in Python 2)
str
objects or (in Python 3)bytes
objects.To learn which attributes are single- or multi-valued, and to learn the type (or, in LDAP terms, the syntax) of an attribute, you need to look at the schema, possibly using
ldap.schema
.cursor provides access to the underlying database, as described in
DBInterface
. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!Warning
Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.
Called to log a change in Syncrepl cookie.
Parameters: cookie (str) – The new Syncrepl cookie. :return None - any returned value is ignored.
This callback happens any time the LDAP server sends us a new Syncrepl cookie.
The Syncrepl cookie is an opaque string, which we send to the LDAP server at the start of a Syncrepl search. If we do not have one, then the LDAP server knows to send us everything. If we do have one, then the LDAP server can use that to know how far behind we are, and to send us just the changes.
This callback can happen in all modes, and in all phases, as it is up to the LDAP server to give us a new Syncrepl cookie, when it is appropriate to do so.
-
classmethod
debug
(message)[source]¶ Called to log debug messages.
Parameters: message (str) – A message of some sort. Returns: None - any returned value is ignored. This method doesn’t have much of a use. It’s just a way for
Syncrepl
to log debug messages. There’s no guarantee that you’ll get anything meaningful, or anything at all.The safest thing to do is to just pass this method. Or, subclass
BaseCallback
.
LoggingCallback¶
-
class
syncrepl_client.callbacks.
LoggingCallback
[source]¶ LoggingCallback
is a callback class which logs each callback. It is useful for debugging purposes, as the output is not meant to be machine-readable.Each callback will cause messages to be printed to the file set in
dest
. For thebind_complete()
callback, the bind DN is printed. For callbacks containing DNs, the DNs are printed. For callbacks containing attribute dictionaries, each dictionary’s contents are printed.For a list of callbacks, and what they mean, see
BaseCallback
.-
dest
= <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>¶ The log destination.
This can be anything which can be used in
print()
‘s file parameter.Defaults to
sys.stdout
.
-