except ImportError:
from pathlib2 import Path
+from functools import cmp_to_key
+
# Third party modules
from ldap3 import Server, Connection, DSA, IP_V4_PREFERRED, SAFE_SYNC
# from ldap3 import ALL
# rom ..config.ldap import DEFAULT_PORT_LDAP, DEFAULT_PORT_LDAPS
from ..config.ldap import DEFAULT_TIMEOUT
-__version__ = '0.8.2'
+__version__ = '0.9.0'
LOG = logging.getLogger(__name__)
_ = XLATOR.gettext
pattern_re_uid = r'^[a-z](?:[a-z0-9\-_.]*[a-z0-9])?$'
re_uid = re.compile(pattern_re_uid, re.IGNORECASE)
+ pattern_dn_separator = r'\s*,\s*'
+ re_dn_separator = re.compile(pattern_dn_separator)
+
person_object_classes = FrozenCIStringSet([
'account', 'inetOrgPerson', 'inetUser', 'posixAccount', 'sambaSamAccount'])
+ # -------------------------------------------------------------------------
+ @classmethod
+ def compare_ldap_dns(cls, x, y):
+
+ # Check for empty DNs
+ if x is None and y is None:
+ return 0
+ if x is None:
+ return -1
+ if y is None:
+ return 1
+
+ # Check for empty FQDNs
+ xs = str(x).strip()
+ ys = str(y).strip()
+
+ if xs == '' and ys == '':
+ return 0
+ if xs == '':
+ return -1
+ if ys == '':
+ return 1
+
+ tokens_x = cls.re_dn_separator.split(xs)
+ tokens_x_rev = list(reversed(tokens_x))
+ tokens_y = cls.re_dn_separator.split(ys)
+ tokens_y_rev = list(reversed(tokens_y))
+
+ if ','.join(tokens_x).lower() == ','.join(tokens_y).lower():
+ return 0
+
+ i = 0
+ while True:
+ j = i + 1
+ if j > len(tokens_x_rev) or j > len(tokens_y_rev):
+ if j <= len(tokens_x_rev):
+ return 1
+ if j <= len(tokens_y_rev):
+ return -1
+ return 0
+ token_x = tokens_x_rev[i]
+ token_y = tokens_y_rev[i]
+ i += 1
+ if token_x.lower() > token_y.lower():
+ return 1
+ if token_x.lower() < token_y.lower():
+ return -1
+
+ # Should never come to here ...
+ LOG.warn("Reached a point, where I never should come.")
+ LOG.debug("Compared x: {x!r} <=> y: {y!r}".format(x=x, y=y))
+ return 0
+
# -------------------------------------------------------------------------
def __init__(
self, appname=None, verbose=0, version=GLOBAL_VERSION, base_dir=None,
LOG.debug(_("Disconnecting from LDAP server {!r} ...").format(connect_info.url))
del self.ldap_server[inst]
+ # -------------------------------------------------------------------------
+ def get_all_entry_dns(self, inst):
+ """Get DNs of all entries in the given LDAP instance and sort them."""
+
+ connect_info = self.cfg.ldap_connection[inst]
+ base_dn = connect_info.base_dn
+ ldap = self.ldap_connection[inst]
+
+ result = []
+ attributes = ['dn']
+ ldap_filter = '(objectClass=*)'
+
+ req_status, req_result, req_response, req_whatever = ldap.search(
+ search_base=base_dn, search_scope=SUBTREE, search_filter=ldap_filter,
+ get_operational_attributes=False, attributes=attributes,
+ time_limit=self.cfg.ldap_timeout)
+
+ if req_status:
+ if self.verbose > 5:
+ msg = _("Result of searching for DNs of all entries:")
+ LOG.debug(msg + '\n' + pp(req_result))
+ for entry in req_response:
+ if self.verbose > 4:
+ LOG.debug(_("Got a response entry:") + ' ' + pp(entry))
+ result.append(entry['dn'])
+
+ else:
+ LOG.warn("Got no entry DNs.")
+
+ if result:
+ result = sorted(result, key=cmp_to_key(self.compare_ldap_dns))
+
+ if self.verbose > 2 and result:
+ LOG.debug(_("Result:") + '\n' + pp(result))
+ return result
+
# -------------------------------------------------------------------------
def get_user_dn(self, user, inst):
from ..argparse_actions import NonNegativeItegerOptionAction
from ..argparse_actions import LimitedFloatOptionAction
-__version__ = '0.2.2'
+__version__ = '0.3.0'
LOG = logging.getLogger(__name__)
_ = XLATOR.gettext
def __init__(self, appname=None, base_dir=None):
self.src_instance = None
- self.src = None
self.tgt_instance = None
- self.tgt = None
+
+ self.src_connect_info = None
+ self.tgt_connect_info = None
+
+ self.src_dns = []
+ self.tgt_dns_current = []
self.limit = 0
self.wait_after_write = self.default_wait_after_write
limit = getattr(self.args, 'limit', 0)
if limit:
- print()
+ self.empty_line()
if self.simulate:
self.limit = limit
LOG.warn(_(
LOG.error(_(
"Limition the number of entries for mirroring may "
"only be done in simulation mode."))
- print()
+ self.empty_line()
self.arg_parser.print_usage(sys.stdout)
self.exit(1)
def _check_source_instance(self):
tgt_name = self.ldap_instances[0]
+ self.tgt_connect_info = self.cfg.ldap_connection[tgt_name]
LOG.debug(_(
"Checking mirror source instance for target instance {!r} ...").format(tgt_name))
"does not exists.").format(src=src_name, tgt=tgt_name)
LOG.error(msg)
self.exit(3)
+ self.src_connect_info = self.cfg.ldap_connection[src_name]
if tgt_name.lower() == src_name.lower():
msg = _("Error in configuration:")
self.tgt_instance = tgt_name
self.ldap_instances.append(src_name)
- # -------------------------------------------------------------------------
- def pre_run(self):
-
- super(MirrorLdapApplication, self).pre_run()
-
- self.src = self.ldap_connection[self.src_instance]
- self.tgt = self.ldap_connection[self.tgt_instance]
-
- # -------------------------------------------------------------------------
- def disconnect_all(self):
-
- self.src = None
- self.tgt = None
-
- super(MirrorLdapApplication, self).disconnect_all()
-
# -------------------------------------------------------------------------
def _run(self):
if not self.quiet and not self.force:
- print()
+ self.empty_line()
src_url = self.cfg.ldap_connection[self.src_instance].url
tgt_url = self.cfg.ldap_connection[self.tgt_instance].url
msg = _(
src=self.src_instance, src_url=src_url, tgt=self.tgt_instance, tgt_url=tgt_url)
self.countdown(number=5, delay=1, prompt=msg)
- if not self.quiet:
- print()
+ self.empty_line()
LOG.info("I'm walking, yes indeed I'm walking ...")
+ self.clean_target_instance()
+
+ # -------------------------------------------------------------------------
+ def clean_target_instance(self):
+ """Cleaning the target instance."""
+
+ self.empty_line()
+ LOG.info(_(
+ "Removing all existing entries in target LDAP instance "
+ "(except the base DN entry, of course)."))
+
+ self.get_current_tgt_entries()
+
+ # -------------------------------------------------------------------------
+ def get_current_tgt_entries(self):
+ """Get DNs of all entries in the target LDAP instance and sort them."""
+
+ LOG.debug(_("Trying to get DNs of all entries in the target LDAP instance."))
+
+ result = self.get_all_entry_dns(self.tgt_instance)
+
# =============================================================================
if __name__ == "__main__":