From 663de835071f48411657a49b844577e547925c5d Mon Sep 17 00:00:00 2001 From: Ilias Stamatis Date: Thu, 10 Aug 2017 14:04:10 +0300 Subject: [PATCH] Issue 46 - dsconf support for dynamic schema reload Description: Add dsconf support for dynamically reloading schema. Notes: Renamed old-style Schema class to SchemaLegacy. https://pagure.io/lib389/issue/46 Author: Ilias95 Review by: ??? --- lib389/__init__.py | 2 +- lib389/cli_conf/schema.py | 17 ++++++++++++++--- lib389/schema.py | 24 +++++++++++++++++++++++- lib389/tasks.py | 7 +++++++ lib389/tests/schema_test.py | 13 ++++++++++++- 5 files changed, 57 insertions(+), 6 deletions(-) mode change 100644 => 100755 lib389/schema.py diff --git a/lib389/__init__.py b/lib389/__init__.py index 43ead6b..359cc15 100644 --- a/lib389/__init__.py +++ b/lib389/__init__.py @@ -305,7 +305,7 @@ class DirSrv(SimpleLDAPObject, object): from lib389.replica import Replicas from lib389.changelog import Changelog from lib389.agreement import Agreement - from lib389.schema import Schema + from lib389.schema import SchemaLegacy as Schema from lib389.plugins import Plugins from lib389.tasks import Tasks from lib389.index import IndexLegacy as Index diff --git a/lib389/cli_conf/schema.py b/lib389/cli_conf/schema.py index 0e1f2a4..49596b5 100644 --- a/lib389/cli_conf/schema.py +++ b/lib389/cli_conf/schema.py @@ -6,9 +6,9 @@ # See LICENSE for details. # --- END COPYRIGHT BLOCK --- -import argparse - from lib389.cli_base import _get_arg +from lib389.schema import Schema + def list_attributetype(inst, basedn, log, args): for attributetype in inst.schema.get_attributetypes(): @@ -16,7 +16,7 @@ def list_attributetype(inst, basedn, log, args): def query_attributetype(inst, basedn, log, args): # Need the query type - attr = _get_arg( args.attr , msg="Enter attribute to query" ) + attr = _get_arg(args.attr, msg="Enter attribute to query") attributetype, must, may = inst.schema.query_attributetype(attr) print(attributetype) print("") @@ -28,6 +28,14 @@ def query_attributetype(inst, basedn, log, args): for oc in may: print(oc) +def reload_schema(inst, basedn, log, args): + schema = Schema(inst) + log.info('Attempting to add task entry... This will fail if Schema Reload plug-in is not enabled.') + task = schema.reload(args.schemadir) + log.info('Successfully added task entry ' + task.dn) + log.info("To verify that the schema reload operation was successful, please check the error logs.") + + def create_parser(subparsers): schema_parser = subparsers.add_parser('schema', help='Query and manipulate schema') @@ -40,3 +48,6 @@ def create_parser(subparsers): query_attributetype_parser.set_defaults(func=query_attributetype) query_attributetype_parser.add_argument('attr', nargs='?', help='Attribute type to query') + reload_parser = subcommands.add_parser('reload', help='Dynamically reload schema while server is running') + reload_parser.set_defaults(func=reload_schema) + reload_parser.add_argument('-d', '--schemadir', help="directory where schema files are located") diff --git a/lib389/schema.py b/lib389/schema.py old mode 100644 new mode 100755 index 6e7f65c..6003093 --- a/lib389/schema.py +++ b/lib389/schema.py @@ -13,11 +13,33 @@ import glob import ldap from ldap.schema.models import AttributeType, ObjectClass, MatchingRule + from lib389._constants import * +from lib389._constants import DN_SCHEMA from lib389.utils import ds_is_newer +from lib389._mapped_object import DSLdapObject +from lib389.tasks import SchemaReloadTask + + +class Schema(DSLdapObject): + def __init__(self, instance, batch=False): + super(Schema, self).__init__(instance=instance, batch=batch) + self._dn = DN_SCHEMA + self._rdn_attribute = 'cn' + + def reload(self, schema_dir=None): + task = SchemaReloadTask(self._instance) + + task_properties = {} + if schema_dir is not None: + task_properties['schemadir'] = schema_dir + + task.create(properties=task_properties) + + return task -class Schema(object): +class SchemaLegacy(object): def __init__(self, conn): """@param conn - a DirSrv instance""" diff --git a/lib389/tasks.py b/lib389/tasks.py index 2c62dce..ec46145 100644 --- a/lib389/tasks.py +++ b/lib389/tasks.py @@ -90,6 +90,13 @@ class USNTombstoneCleanupTask(Task): return super(USNTombstoneCleanupTask, self)._validate(rdn, properties, basedn) +class SchemaReloadTask(Task): + def __init__(self, instance, dn=None, batch=False): + self.cn = 'schema_reload_' + Task._get_task_date() + dn = "cn=" + self.cn + ",cn=schema reload task," + DN_TASKS + + super(SchemaReloadTask, self).__init__(instance, dn, batch) + class Tasks(object): proxied_methods = 'search_s getEntry'.split() diff --git a/lib389/tests/schema_test.py b/lib389/tests/schema_test.py index 20c5a13..28daefe 100644 --- a/lib389/tests/schema_test.py +++ b/lib389/tests/schema_test.py @@ -7,8 +7,10 @@ # --- END COPYRIGHT BLOCK --- # import pytest -from lib389._constants import * + from lib389 import DirSrv +from lib389._constants import SER_HOST, SER_PORT, SER_SERVERID_PROP, LOCALHOST +from lib389.schema import Schema INSTANCE_PORT = 54321 INSTANCE_SERVERID = 'standalone' @@ -53,9 +55,18 @@ def test_schema(topology): assert topology.instance.schema.query_objectclass('account').names == \ ('account', ) +def test_schema_reload(topology): + """Test that the appropriate task entry is created when reloading schema.""" + schema = Schema(topology.instance) + task = schema.reload() + assert task.exists() + task.wait() + assert task.get_exit_code() == 0 + if __name__ == '__main__': # Run isolated # -s for DEBUG mode + import os CURRENT_FILE = os.path.realpath(__file__) pytest.main("-s %s" % CURRENT_FILE) -- 2.13.4