This is an automated email from the git hooks/post-receive script.
firstyear pushed a commit to branch master
in repository 389-ds-base.
commit fbc9b868c7370ae7dfd05f6035a89bd3895c1c55
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Fri Feb 7 11:11:56 2014 +0100
Ticket 47695 - Add plugins/tasks/Index
Bug Description:
Add plugins, tasks and index in lib389
Fix Description:
This creates new modules (index/plugin/tasks).
(some methods from brooker/__init__.py are moved to these modules)
tasks: importLDIF,exportLDIF, reindex, fixupMemberOf
plugins: list, enable, disable
index: addIndex, modIndex, create (wrapper of addIndex).
https://fedorahosted.org/389/ticket/47695
Reviewed by: Rich Megginson
Platforms tested: F19(jenkins)
Flag Day: no
Doc impact: no
---
src/lib389/lib389/__init__.py | 175 +-----------------------
src/lib389/lib389/_constants.py | 18 +++
src/lib389/lib389/backend.py | 11 +-
src/lib389/lib389/brooker.py | 19 ---
src/lib389/lib389/index.py | 74 ++++++++++
src/lib389/lib389/plugins.py | 106 +++++++++++++++
src/lib389/lib389/properties.py | 42 +++++-
src/lib389/lib389/tasks.py | 292 ++++++++++++++++++++++++++++++++++++++++
8 files changed, 548 insertions(+), 189 deletions(-)
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
index ae31427..6be581e 100644
--- a/src/lib389/lib389/__init__.py
+++ b/src/lib389/lib389/__init__.py
@@ -310,8 +310,7 @@ class DirSrv(SimpleLDAPObject):
def __add_brookers__(self):
from lib389.brooker import (
- Config,
- Index)
+ Config)
from lib389.mappingTree import MappingTree
from lib389.backend import Backend
from lib389.suffix import Suffix
@@ -319,6 +318,9 @@ class DirSrv(SimpleLDAPObject):
from lib389.changelog import Changelog
from lib389.agreement import Agreement
from lib389.schema import Schema
+ from lib389.plugins import Plugins
+ from lib389.tasks import Tasks
+ from lib389.index import Index
self.agreement = Agreement(self)
self.replica = Replica(self)
@@ -329,6 +331,8 @@ class DirSrv(SimpleLDAPObject):
self.mappingtree = MappingTree(self)
self.suffix = Suffix(self)
self.schema = Schema(self)
+ self.plugins = Plugins(self)
+ self.tasks = Tasks(self)
def __init__(self, verbose=False, timeout=10):
"""
@@ -1158,137 +1162,6 @@ class DirSrv(SimpleLDAPObject):
if callable(attr):
setattr(self, name, wrapper(attr, name))
- def startTask(self, entry, verbose=False):
- # start the task
- dn = entry.dn
- self.add_s(entry)
-
- if verbose:
- self._test_entry(dn, ldap.SCOPE_BASE)
-
- return True
-
- def checkTask(self, entry, dowait=False, verbose=False):
- '''check task status - task is complete when the nsTaskExitCode attr
is set
- return a 2 tuple (true/false,code) first is false if task is running, true if
- done - if true, second is the exit code - if dowait is True, this function
- will block until the task is complete'''
- attrlist = ['nsTaskLog', 'nsTaskStatus',
'nsTaskExitCode',
- 'nsTaskCurrentItem', 'nsTaskTotalItems']
- done = False
- exitCode = 0
- dn = entry.dn
- while not done:
- entry = self.getEntry(dn, attrlist=attrlist)
- log.debug("task entry %r" % entry)
-
- if entry.nsTaskExitCode:
- exitCode = int(entry.nsTaskExitCode)
- done = True
- if dowait:
- time.sleep(1)
- else:
- break
- return (done, exitCode)
-
- def startTaskAndWait(self, entry, verbose=False):
- self.startTask(entry, verbose)
- (done, exitCode) = self.checkTask(entry, True, verbose)
- return exitCode
-
- def importLDIF(self, ldiffile, suffix, be=None, verbose=False):
- cn = "import" + str(int(time.time()))
- dn = "cn=%s,cn=import,cn=tasks,cn=config" % cn
- entry = Entry(dn)
- entry.setValues('objectclass', 'top',
'extensibleObject')
- entry.setValues('cn', cn)
- entry.setValues('nsFilename', ldiffile)
- if be:
- entry.setValues('nsInstance', be)
- else:
- entry.setValues('nsIncludeSuffix', suffix)
-
- rc = self.startTaskAndWait(entry, verbose)
-
- if rc:
- if verbose:
- log.error("Error: import task %s for file %s exited with %d" %
(
- cn, ldiffile, rc))
- else:
- if verbose:
- log.info("Import task %s for file %s completed successfully" %
(
- cn, ldiffile))
- return rc
-
- def exportLDIF(self, ldiffile, suffix, be=None, forrepl=False, verbose=False):
- cn = "export%d" % time.time()
- dn = "cn=%s,cn=export,cn=tasks,cn=config" % cn
- entry = Entry(dn)
- entry.update({
- 'objectclass': ['top', 'extensibleObject'],
- 'cn': cn,
- 'nsFilename': ldiffile
- })
- if be:
- entry.setValues('nsInstance', be)
- else:
- entry.setValues('nsIncludeSuffix', suffix)
- if forrepl:
- entry.setValues('nsExportReplica', 'true')
-
- rc = self.startTaskAndWait(entry, verbose)
-
- if rc:
- if verbose:
- log.error("Error: export task %s for file %s exited with %d" %
(
- cn, ldiffile, rc))
- else:
- if verbose:
- log.info("Export task %s for file %s completed successfully" %
(
- cn, ldiffile))
- return rc
-
- def createIndex(self, suffix, attr, verbose=False):
- entries_backend = self.backend.list(suffix=suffix)
- cn = "index%d" % time.time()
- dn = "cn=%s,cn=index,cn=tasks,cn=config" % cn
- entry = Entry(dn)
- entry.update({
- 'objectclass': ['top', 'extensibleObject'],
- 'cn': cn,
- 'nsIndexAttribute': attr,
- 'nsInstance': entries_backend[0].cn
- })
- # assume 1 local backend
- rc = self.startTaskAndWait(entry, verbose)
-
- if rc:
- log.error("Error: index task %s exited with %d" % (
- cn, rc))
- else:
- log.info("Index task %s completed successfully" % (
- cn))
- return rc
-
- def fixupMemberOf(self, suffix, filt=None, verbose=False):
- cn = "fixupmemberof%d" % time.time()
- dn = "cn=%s,cn=memberOf task,cn=tasks,cn=config" % cn
- entry = Entry(dn)
- entry.setValues('objectclass', 'top',
'extensibleObject')
- entry.setValues('cn', cn)
- entry.setValues('basedn', suffix)
- if filt:
- entry.setValues('filter', filt)
- rc = self.startTaskAndWait(entry, verbose)
-
- if rc:
- if verbose:
- log.error("Error: fixupMemberOf task %s for basedn %s exited with
%d" % (cn, suffix, rc))
- else:
- if verbose:
- log.info("fixupMemberOf task %s for basedn %s completed
successfully" % (cn, suffix))
- return rc
-
def addLDIF(self, input_file, cont=False):
class LDIFAdder(ldif.LDIFParser):
def __init__(self, input_file, conn, cont=False,
@@ -1503,41 +1376,7 @@ class DirSrv(SimpleLDAPObject):
return entry
- def addIndex(self, suffix, attr, indexTypes, *matchingRules):
- """Specify the suffix (should contain 1 local database backend),
- the name of the attribute to index, and the types of indexes
- to create e.g. "pres", "eq", "sub"
- """
- entries_backend = self.backend.list(suffix=suffix)
- # assume 1 local backend
- dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn)
- entry = Entry(dn)
- entry.setValues('objectclass', 'top', 'nsIndex')
- entry.setValues('cn', attr)
- entry.setValues('nsSystemIndex', "false")
- entry.setValues('nsIndexType', indexTypes)
- if matchingRules:
- entry.setValues('nsMatchingRule', matchingRules)
- try:
- self.add_s(entry)
- except ldap.ALREADY_EXISTS:
- print "Index for attr %s for backend %s already exists" % (
- attr, dn)
-
- def modIndex(self, suffix, attr, mod):
- """just a wrapper around a plain old ldap modify, but will
- find the correct index entry based on the suffix and attribute"""
- entries_backend = self.backend.list(suffix=suffix)
- # assume 1 local backend
- dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn)
- self.modify_s(dn, mod)
-
- def requireIndex(self, suffix):
- entries_backend = self.backend.list(suffix=suffix)
- # assume 1 local backend
- dn = entries_backend[0].dn
- replace = [(ldap.MOD_REPLACE, 'nsslapd-require-index', 'on')]
- self.modify_s(dn, replace)
+
def setupChainingIntermediate(self):
confdn = ','.join(("cn=config", DN_CHAIN))
diff --git a/src/lib389/lib389/_constants.py b/src/lib389/lib389/_constants.py
index 207a3ac..c85acef 100644
--- a/src/lib389/lib389/_constants.py
+++ b/src/lib389/lib389/_constants.py
@@ -93,8 +93,26 @@ DN_CHANGELOG = "cn=changelog5,%s" % DN_CONFIG
DN_LDBM = "cn=ldbm database,%s" % DN_PLUGIN
DN_CHAIN = "cn=chaining database,%s" % DN_PLUGIN
+DN_TASKS = "cn=tasks,%s" % DN_CONFIG
+DN_INDEX_TASK = "cn=index,%s" % DN_TASKS
+DN_MBO_TASK = "cn=memberOf task,%s" % DN_TASKS
+DN_EXPORT_TASK = "cn=export,%s" % DN_TASKS
+DN_IMPORT_TASK = "cn=import,%s" % DN_TASKS
+
RDN_REPLICA = "cn=replica"
+RETROCL_SUFFIX = "cn=changelog"
+
+
+##################################
+###
+### Plugins
+###
+##################################
+
+PLUGIN_RETRO_CHANGELOG = 'Retro Changelog Plugin'
+PLUGIN_MEMBER_OF = 'MemberOf Plugin'
+PLUGIN_REFER_INTEGRITY = 'referential integrity postoperation'
#
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
index e292c04..c341a26 100644
--- a/src/lib389/lib389/backend.py
+++ b/src/lib389/lib389/backend.py
@@ -323,6 +323,15 @@ class Backend(object):
return ent.getValues(attr_suffix)
else:
raise InvalidArgumentError("entry or name are mandatory")
-
+
+ def requireIndex(self, suffix):
+ '''
+ Should be moved in setProperties
+ '''
+ entries_backend = self.backend.list(suffix=suffix)
+ # assume 1 local backend
+ dn = entries_backend[0].dn
+ replace = [(ldap.MOD_REPLACE, 'nsslapd-require-index', 'on')]
+ self.modify_s(dn, replace)
diff --git a/src/lib389/lib389/brooker.py b/src/lib389/lib389/brooker.py
index f8c3099..34453cc 100644
--- a/src/lib389/lib389/brooker.py
+++ b/src/lib389/lib389/brooker.py
@@ -126,22 +126,3 @@ class Config(object):
return self.conn.getEntry(DN_CONFIG, attrlist=fields)
-class Index(object):
-
- def __init__(self, conn):
- """@param conn - a DirSrv instance"""
- self.conn = conn
- self.log = conn.log
-
- def delete_all(self, benamebase):
- dn = "cn=index, cn=" + benamebase + "," + DN_LDBM
-
- # delete each defined index
- ents = self.conn.search_s(dn, ldap.SCOPE_ONELEVEL)
- for ent in ents:
- self.log.debug("Delete index entry %s" % (ent.dn))
- self.conn.delete_s(ent.dn)
-
- # Then delete the top index entry
- self.log.debug("Delete head index entry %s" % (dn))
- self.conn.delete_s(dn)
diff --git a/src/lib389/lib389/index.py b/src/lib389/lib389/index.py
new file mode 100644
index 0000000..fdd8c6b
--- /dev/null
+++ b/src/lib389/lib389/index.py
@@ -0,0 +1,74 @@
+'''
+Created on Feb 11, 2014
+
+@author: tbordaz
+'''
+
+import ldap
+from lib389._constants import *
+from lib389.properties import *
+from lib389 import Entry
+
+
+class Index(object):
+
+ def __init__(self, conn):
+ """@param conn - a DirSrv instance"""
+ self.conn = conn
+ self.log = conn.log
+
+ def delete_all(self, benamebase):
+ dn = "cn=index,cn=" + benamebase + "," + DN_LDBM
+
+ # delete each defined index
+ ents = self.conn.search_s(dn, ldap.SCOPE_ONELEVEL)
+ for ent in ents:
+ self.log.debug("Delete index entry %s" % (ent.dn))
+ self.conn.delete_s(ent.dn)
+
+ # Then delete the top index entry
+ self.log.debug("Delete head index entry %s" % (dn))
+ self.conn.delete_s(dn)
+
+ def create(self, suffix=None, attr=None, args=None):
+ if not suffix:
+ raise ValueError("suffix is mandatory parameter")
+
+ if not attr:
+ raise ValueError("attr is mandatory parameter")
+
+ indexTypes = args.get(INDEX_TYPE, None)
+ matchingRules = args.get(INDEX_MATCHING_RULE, None)
+
+ self.addIndex(suffix, attr, indexTypes=indexTypes, matchingRules=matchingRules)
+
+
+
+ def addIndex(self, suffix, attr, indexTypes, matchingRules):
+ """Specify the suffix (should contain 1 local database backend),
+ the name of the attribute to index, and the types of indexes
+ to create e.g. "pres", "eq", "sub"
+ """
+ entries_backend = self.conn.backend.list(suffix=suffix)
+ # assume 1 local backend
+ dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn)
+ entry = Entry(dn)
+ entry.setValues('objectclass', 'top', 'nsIndex')
+ entry.setValues('cn', attr)
+ entry.setValues('nsSystemIndex', "false")
+ entry.setValues('nsIndexType', indexTypes)
+ if matchingRules:
+ entry.setValues('nsMatchingRule', matchingRules)
+ try:
+ self.conn.add_s(entry)
+ except ldap.ALREADY_EXISTS:
+ print "Index for attr %s for backend %s already exists" % (
+ attr, dn)
+
+ def modIndex(self, suffix, attr, mod):
+ """just a wrapper around a plain old ldap modify, but will
+ find the correct index entry based on the suffix and attribute"""
+ entries_backend = self.conn.backend.list(suffix=suffix)
+ # assume 1 local backend
+ dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn)
+ self.conn.modify_s(dn, mod)
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
new file mode 100644
index 0000000..5e847c7
--- /dev/null
+++ b/src/lib389/lib389/plugins.py
@@ -0,0 +1,106 @@
+'''
+Created on Jan 14, 2014
+
+@author: tbordaz
+'''
+
+import ldap
+from lib389 import DirSrv, InvalidArgumentError
+from lib389.properties import *
+from lib389._constants import *
+
+
+class Plugins(object):
+
+ proxied_methods = 'search_s getEntry'.split()
+
+ def __init__(self, conn):
+ """@param conn - a DirSrv instance"""
+ self.conn = conn
+ self.log = conn.log
+
+ def __getattr__(self, name):
+ if name in Plugins.proxied_methods:
+ return DirSrv.__getattr__(self.conn, name)
+
+ def list(self, name=None):
+ '''
+ Returns a search result of the plugins entries with all their attributes
+
+ If 'name' is not specified, it returns all the plugins, else it
returns the plugin
+ matching ('cn=<name>, DN_PLUGIN')
+
+ @param name - name of the plugin
+
+ @return plugin entries
+
+ @raise None
+
+ '''
+
+ if name:
+ filt = "(objectclass=%s)" % PLUGINS_OBJECTCLASS_VALUE
+ base = "cn=%s,%s" % (name, DN_PLUGIN)
+ scope = ldap.SCOPE_BASE
+ else:
+ filt = "(objectclass=%s)" % PLUGINS_OBJECTCLASS_VALUE
+ base = DN_PLUGIN
+ scope = ldap.SCOPE_ONELEVEL
+
+ ents = self.conn.search_s(base, scope, filt)
+ return ents
+
+ def enable(self, name=None, plugin_dn=None):
+ '''
+ Enable a plugin
+
+ If 'plugin_dn' and 'name' are provided, plugin_dn is used and
'name is not considered
+
+ @param name - name of the plugin
+ @param plugin_dn - DN of the plugin
+
+ @return None
+
+ @raise ValueError - if 'name' or 'plugin_dn' lead to unknown
plugin
+ InvalidArgumentError - if 'name' and 'plugin_dn' are
missing
+ '''
+
+ dn = plugin_dn or "cn=%s,%s" % (name, DN_PLUGIN)
+ filt = "(objectclass=%s)" % PLUGINS_OBJECTCLASS_VALUE
+
+ if not dn:
+ raise InvalidArgumentError("plugin 'name' and
'plugin_dn' are missing")
+
+ ents = self.conn.search_s(dn, ldap.SCOPE_BASE, filt)
+ if len(ents) != 1:
+ raise ValueError("%s is unknown")
+
+ self.conn.modify_s(dn, [(ldap.MOD_REPLACE,
PLUGIN_PROPNAME_TO_ATTRNAME[PLUGIN_ENABLE], PLUGINS_ENABLE_ON_VALUE)])
+
+ def disable(self, name=None, plugin_dn=None):
+ '''
+ Disable a plugin
+
+ If 'plugin_dn' and 'name' are provided, plugin_dn is used and
'name is not considered
+
+ @param name - name of the plugin
+ @param plugin_dn - DN of the plugin
+
+ @return None
+
+ @raise ValueError - if 'name' or 'plugin_dn' lead to unknown
plugin
+ InvalidArgumentError - if 'name' and 'plugin_dn' are
missing
+ '''
+
+ dn = plugin_dn or "cn=%s,%s" % (name, DN_PLUGIN)
+ filt = "(objectclass=%s)" % PLUGINS_OBJECTCLASS_VALUE
+
+ if not dn:
+ raise InvalidArgumentError("plugin 'name' and
'plugin_dn' are missing")
+
+ ents = self.conn.search_s(dn, ldap.SCOPE_BASE, filt)
+ if len(ents) != 1:
+ raise ValueError("%s is unknown")
+
+ self.conn.modify_s(dn, [(ldap.MOD_REPLACE,
PLUGIN_PROPNAME_TO_ATTRNAME[PLUGIN_ENABLE], PLUGINS_ENABLE_ON_VALUE)])
+
diff --git a/src/lib389/lib389/properties.py b/src/lib389/lib389/properties.py
index 4b5184a..73bfd29 100644
--- a/src/lib389/lib389/properties.py
+++ b/src/lib389/lib389/properties.py
@@ -4,7 +4,6 @@ Created on Dec 5, 2013
@author: tbordaz
'''
-
####################################
#
# Properties supported by the server
@@ -218,6 +217,47 @@ RA_PROPNAME_TO_ATTRNAME = {RA_NAME: 'cn',
RA_TIMEOUT: 'nsds5replicatimeout',
RA_CHANGES:
'nsds5replicaChangesSentSinceStartup'}
+####################################
+#
+# Properties supported by the plugins
+#
+####################################
+
+PLUGIN_NAME = "name"
+PLUGIN_PATH = "path"
+PLUGIN_ENABLE = 'enable'
+
+PLUGINS_OBJECTCLASS_VALUE = "nsSlapdPlugin"
+PLUGINS_ENABLE_ON_VALUE = "on"
+PLUGINS_ENABLE_OFF_VALUE = "off"
+
+PLUGIN_PROPNAME_TO_ATTRNAME = {PLUGIN_NAME: 'cn',
+ PLUGIN_PATH: 'nsslapd-pluginPath',
+ PLUGIN_ENABLE: 'nsslapd-pluginEnabled'}
+
+####################################
+#
+# Properties supported by the index
+#
+####################################
+INDEX_TYPE = "type"
+INDEX_SYSTEM = "system"
+INDEX_MATCHING_RULE = "matching-rule"
+
+INDEX_PROPNAME_TO_ATTRNAME = {INDEX_TYPE: 'nsIndexType',
+ INDEX_SYSTEM: 'nsSystemIndex',
+ INDEX_MATCHING_RULE: 'nsMatchingRule'}
+
+####################################
+#
+# Properties supported by the tasks
+#
+####################################
+
+TASK_WAIT = "wait"
+EXPORT_REPL_INFO = "repl-info"
+
+
def rawProperty(prop):
'''
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
new file mode 100644
index 0000000..f61f935
--- /dev/null
+++ b/src/lib389/lib389/tasks.py
@@ -0,0 +1,292 @@
+'''
+Created on Feb 10, 2014
+
+@author: tbordaz
+'''
+from lib389 import DirSrv, Entry
+from lib389._constants import *
+from lib389.properties import *
+import ldap
+import time
+
+class Tasks(object):
+ proxied_methods = 'search_s getEntry'.split()
+
+ def __init__(self, conn):
+ """@param conn - a DirSrv instance"""
+ self.conn = conn
+ self.log = conn.log
+
+ def __getattr__(self, name):
+ if name in Tasks.proxied_methods:
+ return DirSrv.__getattr__(self.conn, name)
+
+ def checkTask(self, entry, dowait=False):
+ '''check task status - task is complete when the nsTaskExitCode attr
is set
+ return a 2 tuple (true/false,code) first is false if task is running, true if
+ done - if true, second is the exit code - if dowait is True, this function
+ will block until the task is complete'''
+ attrlist = ['nsTaskLog', 'nsTaskStatus',
'nsTaskExitCode',
+ 'nsTaskCurrentItem', 'nsTaskTotalItems']
+ done = False
+ exitCode = 0
+ dn = entry.dn
+ while not done:
+ entry = self.conn.getEntry(dn, attrlist=attrlist)
+ self.log.debug("task entry %r" % entry)
+
+ if entry.nsTaskExitCode:
+ exitCode = int(entry.nsTaskExitCode)
+ done = True
+ if dowait:
+ time.sleep(1)
+ else:
+ break
+ return (done, exitCode)
+
+ def importLDIF(self, suffix=None, benamebase=None, input_file=None, args=None):
+ '''
+ Import from a LDIF format a given 'suffix' (or 'benamebase' that
stores that suffix).
+ It uses an internal task to acheive this request.
+
+ If 'suffix' and 'benamebase' are specified, it uses
'benamebase' first else 'suffix'.
+ If both 'suffix' and 'benamebase' are missing it raise
ValueError
+
+ 'input_file' is the ldif input file
+
+ @param suffix - suffix of the backend
+ @param benamebase - 'commonname'/'cn' of the backend (e.g.
'userRoot')
+ @param ldif_input - file that will contain the entries in LDIF format, to import
+ @param args - is a dictionary that contains modifier of the import task
+ wait: True/[False] - If True, 'export' waits for the completion
of the task before to return
+
+ @return None
+
+ @raise ValueError
+
+ '''
+ # Checking the parameters
+ if not benamebase and not suffix:
+ raise ValueError("Specify either bename or suffix")
+
+ if not input_file:
+ raise ValueError("input_file is mandatory")
+
+ # Prepare the task entry
+ cn = "import" + str(int(time.time()))
+ dn = "cn=%s,%s" % (cn, DN_IMPORT_TASK)
+ entry = Entry(dn)
+ entry.setValues('objectclass', 'top',
'extensibleObject')
+ entry.setValues('cn', cn)
+ entry.setValues('nsFilename', input_file)
+ if benamebase:
+ entry.setValues('nsInstance', benamebase)
+ else:
+ entry.setValues('nsIncludeSuffix', suffix)
+
+ # start the task and possibly wait for task completion
+ try:
+ self.conn.add_s(entry)
+ except ldap.ALREADY_EXISTS:
+ self.log.error("Fail to add the import task of %s" % input_file)
+ return -1
+
+ exitCode = 0
+ if args and args.get(TASK_WAIT, False):
+ (done, exitCode) = self.conn.tasks.checkTask(entry, True)
+
+ if exitCode:
+ self.log.error("Error: import task %s for file %s exited with %d" %
(
+ cn, input_file, exitCode))
+ else:
+ self.log.info("Import task %s for file %s completed successfully" %
(
+ cn, input_file))
+ return exitCode
+
+ def exportLDIF(self, suffix=None, benamebase=None, output_file=None, args=None):
+ '''
+ Export in a LDIF format a given 'suffix' (or 'benamebase' that
stores that suffix).
+ It uses an internal task to acheive this request.
+
+ If 'suffix' and 'benamebase' are specified, it uses
'benamebase' first else 'suffix'.
+ If both 'suffix' and 'benamebase' are missing it raises
ValueError
+
+ 'output_file' is the output file of the export
+
+ @param suffix - suffix of the backend
+ @param benamebase - 'commonname'/'cn' of the backend (e.g.
'userRoot')
+ @param output_file - file that will contain the exported suffix in LDIF format
+ @param args - is a dictionary that contains modifier of the export task
+ wait: True/[False] - If True, 'export' waits for the completion
of the task before to return
+ repl-info: True/[False] - If True, it adds the replication meta data
(state information, tombstones and RUV) in the exported file
+
+ @return None
+
+ @raise ValueError
+
+ '''
+
+ # Checking the parameters
+ if not benamebase and not suffix:
+ raise ValueError("Specify either bename or suffix")
+
+ if not output_file:
+ raise ValueError("output_file is mandatory")
+
+ # Prepare the task entry
+ cn = "export%d" % time.time()
+ dn = "cn=%s,%s" % (cn, DN_EXPORT_TASK)
+ entry = Entry(dn)
+ entry.update({
+ 'objectclass': ['top', 'extensibleObject'],
+ 'cn': cn,
+ 'nsFilename': output_file
+ })
+ if benamebase:
+ entry.setValues('nsInstance', benamebase)
+ else:
+ entry.setValues('nsIncludeSuffix', suffix)
+
+ if args.get(EXPORT_REPL_INFO, False):
+ entry.setValues('nsExportReplica', 'true')
+
+ # start the task and possibly wait for task completion
+ self.conn.add_s(entry)
+ exitCode = 0
+ if args and args.get(TASK_WAIT, False):
+ (done, exitCode) = self.conn.tasks.checkTask(entry, True)
+
+
+ if exitCode:
+ self.log.error("Error: export task %s for file %s exited with %d" %
(
+ cn, output_file, exitCode))
+ else:
+ self.log.info("Export task %s for file %s completed successfully" %
(
+ cn, output_file))
+ return exitCode
+
+
+ def reindex(self, suffix=None, benamebase=None, attrname=None, args=None):
+ '''
+ Reindex a 'suffix' (or 'benamebase' that stores that suffix) for
a given 'attrname'.
+ It uses an internal task to acheive this request.
+
+ If 'suffix' and 'benamebase' are specified, it uses
'benamebase' first else 'suffix'.
+ If both 'suffix' and 'benamebase' are missing it raise
ValueError
+
+ @param suffix - suffix of the backend
+ @param benamebase - 'commonname'/'cn' of the backend (e.g.
'userRoot')
+ @param attrname - attribute name
+ @param args - is a dictionary that contains modifier of the reindex task
+ wait: True/[False] - If True, 'index' waits for the completion of
the task before to return
+
+ @return None
+
+ @raise ValueError if invalid missing benamebase and suffix or invalid benamebase
+
+ '''
+ if not benamebase and not suffix:
+ raise ValueError("Specify either bename or suffix")
+
+ # If backend name was provided, retrieve the suffix
+ if benamebase:
+ ents = self.conn.mappingtree.list(bename=benamebase)
+ if len(ents) != 1:
+ raise ValueError("invalid backend name: %s" % benamebase)
+
+ attr_suffix = MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]
+ if not ents[0].hasAttr(attr_suffix):
+ raise ValueError("invalid backend name: %s, or entry without
%s" % (benamebase, attr_suffix))
+
+ suffix = ents[0].getValue(attr_suffix)
+
+ entries_backend = self.conn.backend.list(suffix=suffix)
+ cn = "index_%s_%d" % (attrname, time.time())
+ dn = "cn=%s,%s" % (cn, DN_INDEX_TASK)
+ entry = Entry(dn)
+ entry.update({
+ 'objectclass': ['top', 'extensibleObject'],
+ 'cn': cn,
+ 'nsIndexAttribute': attrname,
+ 'nsInstance': entries_backend[0].cn
+ })
+ # assume 1 local backend
+
+ # start the task and possibly wait for task completion
+ try:
+ self.conn.add_s(entry)
+ except ldap.ALREADY_EXISTS:
+ self.log.error("Fail to add the index task for %s" % attrname)
+ return -1
+
+ exitCode = 0
+ if args and args.get(TASK_WAIT, False):
+ (done, exitCode) = self.conn.tasks.checkTask(entry, True)
+
+ if exitCode:
+ self.log.error("Error: index task %s exited with %d" % (
+ cn, exitCode))
+ else:
+ self.log.info("Index task %s completed successfully" % (
+ cn))
+ return exitCode
+
+ def fixupMemberOf(self, suffix=None, benamebase=None, filt=None, args=None):
+ '''
+ Trigger a fixup task on 'suffix' (or 'benamebase' that stores
that suffix) related to the
+ entries 'memberof' of groups. It uses an internal task to acheive
this request.
+
+ If 'suffix' and 'benamebase' are specified, it uses
'benamebase' first else 'suffix'.
+ If both 'suffix' and 'benamebase' are missing it raise
ValueError
+
+ 'filt' is a filter that will select all the entries (under
'suffix') that we need to evaluate/fix.
+ If missing, the default value is
"(|(objectclass=inetuser)(objectclass=inetadmin))"
+
+ @param suffix - suffix of the backend
+ @param benamebase - 'commonname'/'cn' of the backend (e.g.
'userRoot')
+ @param args - is a dictionary that contains modifier of the fixupMemberOf
task
+ wait: True/[False] - If True, waits for the completion of the task
before to return
+
+
+ @return None
+
+ @raise ValueError: if benamebase and suffix are specified, or can not
retrieve the suffix from the
+ mapping tree entry
+ '''
+ if not benamebase and not suffix:
+ raise ValueError("Specify either bename or suffix")
+
+ # If backend name was provided, retrieve the suffix
+ if benamebase:
+ ents = self.conn.mappingtree.list(bename=benamebase)
+ if len(ents) != 1:
+ raise ValueError("invalid backend name: %s" % benamebase)
+
+ attr = MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]
+ if not ents[0].hasAttr(attr):
+ raise ValueError("invalid backend name: %s, or entry without
%s" % (benamebase, attr))
+
+ suffix = ents[0].getValue(attr)
+
+ cn = "fixupmemberof%d" % time.time()
+ dn = "cn=%s,%s" % (cn, DN_MBO_TASK)
+ entry = Entry(dn)
+ entry.setValues('objectclass', 'top',
'extensibleObject')
+ entry.setValues('cn', cn)
+ entry.setValues('basedn', suffix)
+ if filt:
+ entry.setValues('filter', filt)
+
+ # start the task and possibly wait for task completion
+ self.conn.add_s(entry)
+ exitCode = 0
+ if args and args.get(TASK_WAIT, False):
+ (done, exitCode) = self.conn.tasks.checkTask(entry, True)
+
+
+ if exitCode:
+ self.log.error("Error: fixupMemberOf task %s for basedn %s exited with
%d" % (cn, suffix, exitCode))
+ else:
+ self.log.info("fixupMemberOf task %s for basedn %s completed
successfully" % (cn, suffix))
+ return exitCode
+
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.