import 389-ds-base-1.4.3.16-4.module+el8.4.0+8992+caadce03

This commit is contained in:
CentOS Sources 2020-12-08 10:18:10 +00:00
parent 47c2e97085
commit 3bc51ab8ba
3 changed files with 1414 additions and 1 deletions

View file

@ -0,0 +1,502 @@
From 4faec52810e12070ef72da347bb590c57d8761e4 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Fri, 20 Nov 2020 17:47:18 -0500
Subject: [PATCH 1/2] Issue 3657 - Add options to dsctl for dsrc file
Description: Add options to create, modify, delete, and display
the .dsrc CLI tool shortcut file.
Relates: https://github.com/389ds/389-ds-base/issues/3657
Reviewed by: firstyear(Thanks!)
---
dirsrvtests/tests/suites/clu/dsrc_test.py | 136 ++++++++++
src/lib389/cli/dsctl | 2 +
src/lib389/lib389/cli_ctl/dsrc.py | 312 ++++++++++++++++++++++
3 files changed, 450 insertions(+)
create mode 100644 dirsrvtests/tests/suites/clu/dsrc_test.py
create mode 100644 src/lib389/lib389/cli_ctl/dsrc.py
diff --git a/dirsrvtests/tests/suites/clu/dsrc_test.py b/dirsrvtests/tests/suites/clu/dsrc_test.py
new file mode 100644
index 000000000..1b27700ec
--- /dev/null
+++ b/dirsrvtests/tests/suites/clu/dsrc_test.py
@@ -0,0 +1,136 @@
+import logging
+import pytest
+import os
+from os.path import expanduser
+from lib389.cli_base import FakeArgs
+from lib389.cli_ctl.dsrc import create_dsrc, modify_dsrc, delete_dsrc, display_dsrc
+from lib389._constants import DEFAULT_SUFFIX, DN_DM
+from lib389.topologies import topology_st as topo
+
+log = logging.getLogger(__name__)
+
+
+@pytest.fixture(scope="function")
+def setup(topo, request):
+ """Preserve any existing .dsrc file"""
+
+ dsrc_file = f'{expanduser("~")}/.dsrc'
+ backup_file = dsrc_file + ".original"
+ if os.path.exists(dsrc_file):
+ os.rename(dsrc_file, backup_file)
+
+ def fin():
+ if os.path.exists(backup_file):
+ os.rename(backup_file, dsrc_file)
+
+ request.addfinalizer(fin)
+
+
+def test_dsrc(topo, setup):
+ """Test "dsctl dsrc" command
+
+ :id: 0610de6c-e167-4761-bdab-3e677b2d44bb
+ :setup: Standalone Instance
+ :steps:
+ 1. Test creation works
+ 2. Test creating duplicate section
+ 3. Test adding an additional inst config works
+ 4. Test removing an instance works
+ 5. Test modify works
+ 6. Test delete works
+ 7. Test display fails when no file is present
+
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ 5. Success
+ 6. Success
+ 7. Success
+ """
+
+ inst = topo.standalone
+ serverid = inst.serverid
+ second_inst_name = "Second"
+ second_inst_basedn = "o=second"
+ different_suffix = "o=different"
+
+ # Setup our args
+ args = FakeArgs()
+ args.basedn = DEFAULT_SUFFIX
+ args.binddn = DN_DM
+ args.json = None
+ args.uri = None
+ args.saslmech = None
+ args.tls_cacertdir = None
+ args.tls_cert = None
+ args.tls_key = None
+ args.tls_reqcert = None
+ args.starttls = None
+ args.cancel_starttls = None
+ args.pwdfile = None
+ args.do_it = True
+
+ # Create a dsrc configuration entry
+ create_dsrc(inst, log, args)
+ display_dsrc(inst, topo.logcap.log, args)
+ assert topo.logcap.contains("basedn = " + args.basedn)
+ assert topo.logcap.contains("binddn = " + args.binddn)
+ assert topo.logcap.contains("[" + serverid + "]")
+ topo.logcap.flush()
+
+ # Attempt to add duplicate instance section
+ with pytest.raises(ValueError):
+ create_dsrc(inst, log, args)
+
+ # Test adding a second instance works correctly
+ inst.serverid = second_inst_name
+ args.basedn = second_inst_basedn
+ create_dsrc(inst, log, args)
+ display_dsrc(inst, topo.logcap.log, args)
+ assert topo.logcap.contains("basedn = " + args.basedn)
+ assert topo.logcap.contains("[" + second_inst_name + "]")
+ topo.logcap.flush()
+
+ # Delete second instance
+ delete_dsrc(inst, log, args)
+ inst.serverid = serverid # Restore original instance name
+ display_dsrc(inst, topo.logcap.log, args)
+ assert not topo.logcap.contains("[" + second_inst_name + "]")
+ assert not topo.logcap.contains("basedn = " + args.basedn)
+ # Make sure first instance config is still present
+ assert topo.logcap.contains("[" + serverid + "]")
+ assert topo.logcap.contains("binddn = " + args.binddn)
+ topo.logcap.flush()
+
+ # Modify the config
+ args.basedn = different_suffix
+ modify_dsrc(inst, log, args)
+ display_dsrc(inst, topo.logcap.log, args)
+ assert topo.logcap.contains(different_suffix)
+ topo.logcap.flush()
+
+ # Remove an arg from the config
+ args.basedn = ""
+ modify_dsrc(inst, log, args)
+ display_dsrc(inst, topo.logcap.log, args)
+ assert not topo.logcap.contains(different_suffix)
+ topo.logcap.flush()
+
+ # Remove the last entry, which should delete the file
+ delete_dsrc(inst, log, args)
+ dsrc_file = f'{expanduser("~")}/.dsrc'
+ assert not os.path.exists(dsrc_file)
+
+ # Make sure display fails
+ with pytest.raises(ValueError):
+ display_dsrc(inst, log, args)
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl
index fe9bc10e9..69f069297 100755
--- a/src/lib389/cli/dsctl
+++ b/src/lib389/cli/dsctl
@@ -23,6 +23,7 @@ from lib389.cli_ctl import tls as cli_tls
from lib389.cli_ctl import health as cli_health
from lib389.cli_ctl import nsstate as cli_nsstate
from lib389.cli_ctl import dbgen as cli_dbgen
+from lib389.cli_ctl import dsrc as cli_dsrc
from lib389.cli_ctl.instance import instance_remove_all
from lib389.cli_base import (
disconnect_instance,
@@ -61,6 +62,7 @@ cli_tls.create_parser(subparsers)
cli_health.create_parser(subparsers)
cli_nsstate.create_parser(subparsers)
cli_dbgen.create_parser(subparsers)
+cli_dsrc.create_parser(subparsers)
argcomplete.autocomplete(parser)
diff --git a/src/lib389/lib389/cli_ctl/dsrc.py b/src/lib389/lib389/cli_ctl/dsrc.py
new file mode 100644
index 000000000..e49c7f819
--- /dev/null
+++ b/src/lib389/lib389/cli_ctl/dsrc.py
@@ -0,0 +1,312 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2020 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+
+import json
+from os.path import expanduser
+from os import path, remove
+from ldapurl import isLDAPUrl
+from ldap.dn import is_dn
+import configparser
+
+
+def create_dsrc(inst, log, args):
+ """Create the .dsrc file
+
+ [instance]
+ uri = ldaps://hostname:port
+ basedn = dc=example,dc=com
+ binddn = uid=user,....
+ saslmech = [EXTERNAL|PLAIN]
+ tls_cacertdir = /path/to/cacertdir
+ tls_cert = /path/to/user.crt
+ tls_key = /path/to/user.key
+ tls_reqcert = [never, hard, allow]
+ starttls = [true, false]
+ pwdfile = /path/to/file
+ """
+
+ dsrc_file = f'{expanduser("~")}/.dsrc'
+ config = configparser.ConfigParser()
+ config.read(dsrc_file)
+
+ # Verify this section does not already exist
+ instances = config.sections()
+ if inst.serverid in instances:
+ raise ValueError("There is already a configuration section for this instance!")
+
+ # Process and validate the args
+ config[inst.serverid] = {}
+
+ if args.uri is not None:
+ if not isLDAPUrl(args.uri):
+ raise ValueError("The uri is not a valid LDAP URL!")
+ if args.uri.startswith("ldapi"):
+ # We must use EXTERNAL saslmech for LDAPI
+ args.saslmech = "EXTERNAL"
+ config[inst.serverid]['uri'] = args.uri
+ if args.basedn is not None:
+ if not is_dn(args.basedn):
+ raise ValueError("The basedn is not a valid DN!")
+ config[inst.serverid]['basedn'] = args.basedn
+ if args.binddn is not None:
+ if not is_dn(args.binddn):
+ raise ValueError("The binddn is not a valid DN!")
+ config[inst.serverid]['binddn'] = args.binddn
+ if args.saslmech is not None:
+ if args.saslmech not in ['EXTERNAL', 'PLAIN']:
+ raise ValueError("The saslmech must be EXTERNAL or PLAIN!")
+ config[inst.serverid]['saslmech'] = args.saslmech
+ if args.tls_cacertdir is not None:
+ if not path.exists(args.tls_cacertdir):
+ raise ValueError('--tls-cacertdir directory does not exist!')
+ config[inst.serverid]['tls_cacertdir'] = args.tls_cacertdir
+ if args.tls_cert is not None:
+ if not path.exists(args.tls_cert):
+ raise ValueError('--tls-cert does not point to an existing file!')
+ config[inst.serverid]['tls_cert'] = args.tls_cert
+ if args.tls_key is not None:
+ if not path.exists(args.tls_key):
+ raise ValueError('--tls-key does not point to an existing file!')
+ config[inst.serverid]['tls_key'] = args.tls_key
+ if args.tls_reqcert is not None:
+ if args.tls_reqcert not in ['never', 'hard', 'allow']:
+ raise ValueError('--tls-reqcert value is invalid (must be either "never", "allow", or "hard")!')
+ config[inst.serverid]['tls_reqcert'] = args.tls_reqcert
+ if args.starttls:
+ config[inst.serverid]['starttls'] = 'true'
+ if args.pwdfile is not None:
+ if not path.exists(args.pwdfile):
+ raise ValueError('--pwdfile does not exist!')
+ config[inst.serverid]['pwdfile'] = args.pwdfile
+
+ if len(config[inst.serverid]) == 0:
+ # No args set
+ raise ValueError("You must set at least one argument for the new dsrc file!")
+
+ # Print a preview of the config
+ log.info(f'Updating "{dsrc_file}" with:\n')
+ log.info(f' [{inst.serverid}]')
+ for k, v in config[inst.serverid].items():
+ log.info(f' {k} = {v}')
+
+ # Perform confirmation?
+ if not args.do_it:
+ while 1:
+ val = input(f'\nUpdate "{dsrc_file}" ? [yes]: ').rstrip().lower()
+ if val == '' or val == 'y' or val == 'yes':
+ break
+ if val == 'n' or val == 'no':
+ return
+
+ # Now write the file
+ with open(dsrc_file, 'w') as configfile:
+ config.write(configfile)
+
+ log.info(f'Successfully updated: {dsrc_file}')
+
+
+def modify_dsrc(inst, log, args):
+ """Modify the instance config
+ """
+ dsrc_file = f'{expanduser("~")}/.dsrc'
+
+ if path.exists(dsrc_file):
+ config = configparser.ConfigParser()
+ config.read(dsrc_file)
+
+ # Verify we have a section to modify
+ instances = config.sections()
+ if inst.serverid not in instances:
+ raise ValueError("There is no configuration section for this instance to modify!")
+
+ # Process and validate the args
+ if args.uri is not None:
+ if not isLDAPUrl(args.uri):
+ raise ValueError("The uri is not a valid LDAP URL!")
+ if args.uri.startswith("ldapi"):
+ # We must use EXTERNAL saslmech for LDAPI
+ args.saslmech = "EXTERNAL"
+ if args.uri == '':
+ del config[inst.serverid]['uri']
+ else:
+ config[inst.serverid]['uri'] = args.uri
+ if args.basedn is not None:
+ if not is_dn(args.basedn):
+ raise ValueError("The basedn is not a valid DN!")
+ if args.basedn == '':
+ del config[inst.serverid]['basedn']
+ else:
+ config[inst.serverid]['basedn'] = args.basedn
+ if args.binddn is not None:
+ if not is_dn(args.binddn):
+ raise ValueError("The binddn is not a valid DN!")
+ if args.binddn == '':
+ del config[inst.serverid]['binddn']
+ else:
+ config[inst.serverid]['binddn'] = args.binddn
+ if args.saslmech is not None:
+ if args.saslmech not in ['EXTERNAL', 'PLAIN']:
+ raise ValueError("The saslmech must be EXTERNAL or PLAIN!")
+ if args.saslmech == '':
+ del config[inst.serverid]['saslmech']
+ else:
+ config[inst.serverid]['saslmech'] = args.saslmech
+ if args.tls_cacertdir is not None:
+ if not path.exists(args.tls_cacertdir):
+ raise ValueError('--tls-cacertdir directory does not exist!')
+ if args.tls_cacertdir == '':
+ del config[inst.serverid]['tls_cacertdir']
+ else:
+ config[inst.serverid]['tls_cacertdir'] = args.tls_cacertdir
+ if args.tls_cert is not None:
+ if not path.exists(args.tls_cert):
+ raise ValueError('--tls-cert does not point to an existing file!')
+ if args.tls_cert == '':
+ del config[inst.serverid]['tls_cert']
+ else:
+ config[inst.serverid]['tls_cert'] = args.tls_cert
+ if args.tls_key is not None:
+ if not path.exists(args.tls_key):
+ raise ValueError('--tls-key does not point to an existing file!')
+ if args.tls_key == '':
+ del config[inst.serverid]['tls_key']
+ else:
+ config[inst.serverid]['tls_key'] = args.tls_key
+ if args.tls_reqcert is not None:
+ if args.tls_reqcert not in ['never', 'hard', 'allow']:
+ raise ValueError('--tls-reqcert value is invalid (must be either "never", "allow", or "hard")!')
+ if args.tls_reqcert == '':
+ del config[inst.serverid]['tls_reqcert']
+ else:
+ config[inst.serverid]['tls_reqcert'] = args.tls_reqcert
+ if args.starttls:
+ config[inst.serverid]['starttls'] = 'true'
+ if args.cancel_starttls:
+ config[inst.serverid]['starttls'] = 'false'
+ if args.pwdfile is not None:
+ if not path.exists(args.pwdfile):
+ raise ValueError('--pwdfile does not exist!')
+ if args.pwdfile == '':
+ del config[inst.serverid]['pwdfile']
+ else:
+ config[inst.serverid]['pwdfile'] = args.pwdfile
+
+ # Okay now rewrite the file
+ with open(dsrc_file, 'w') as configfile:
+ config.write(configfile)
+
+ log.info(f'Successfully updated: {dsrc_file}')
+ else:
+ raise ValueError(f'There is no .dsrc file "{dsrc_file}" to update!')
+
+
+def delete_dsrc(inst, log, args):
+ """Delete the .dsrc file
+ """
+ dsrc_file = f'{expanduser("~")}/.dsrc'
+ if path.exists(dsrc_file):
+ if not args.do_it:
+ # Get confirmation
+ while 1:
+ val = input(f'\nAre you sure you want to remove this instances configuration ? [no]: ').rstrip().lower()
+ if val == 'y' or val == 'yes':
+ break
+ if val == '' or val == 'n' or val == 'no':
+ return
+
+ config = configparser.ConfigParser()
+ config.read(dsrc_file)
+ instances = config.sections()
+ if inst.serverid not in instances:
+ raise ValueError("The is no configuration for this instance")
+
+ # Update the config object
+ del config[inst.serverid]
+
+ if len(config.sections()) == 0:
+ # The file would be empty so just delete it
+ try:
+ remove(dsrc_file)
+ log.info(f'Successfully removed: {dsrc_file}')
+ return
+ except OSError as e:
+ raise ValueError(f'Failed to delete "{dsrc_file}", error: {str(e)}')
+ else:
+ # write the updated config
+ with open(dsrc_file, 'w') as configfile:
+ config.write(configfile)
+ else:
+ raise ValueError(f'There is no .dsrc file "{dsrc_file}" to update!')
+
+ log.info(f'Successfully updated: {dsrc_file}')
+
+def display_dsrc(inst, log, args):
+ """Display the contents of the ~/.dsrc file
+ """
+ dsrc_file = f'{expanduser("~")}/.dsrc'
+
+ if not path.exists(dsrc_file):
+ raise ValueError(f'There is no dsrc file "{dsrc_file}" to display!')
+
+ config = configparser.ConfigParser()
+ config.read(dsrc_file)
+ instances = config.sections()
+
+ for inst_section in instances:
+ if args.json:
+ log.info(json.dumps({inst_section: dict(config[inst_section])}, indent=4))
+ else:
+ log.info(f'[{inst_section}]')
+ for k, v in config[inst_section].items():
+ log.info(f'{k} = {v}')
+ log.info("")
+
+
+def create_parser(subparsers):
+ dsrc_parser = subparsers.add_parser('dsrc', help="Manage the .dsrc file")
+ subcommands = dsrc_parser.add_subparsers(help="action")
+
+ # Create .dsrc file
+ dsrc_create_parser = subcommands.add_parser('create', help='Generate the .dsrc file')
+ dsrc_create_parser.set_defaults(func=create_dsrc)
+ dsrc_create_parser.add_argument('--uri', help="The URI (LDAP URL) for the Directory Server instance.")
+ dsrc_create_parser.add_argument('--basedn', help="The default database suffix.")
+ dsrc_create_parser.add_argument('--binddn', help="The default Bind DN used or authentication.")
+ dsrc_create_parser.add_argument('--saslmech', help="The SASL mechanism to use: PLAIN or EXTERNAL.")
+ dsrc_create_parser.add_argument('--tls-cacertdir', help="The directory containing the Trusted Certificate Authority certificate.")
+ dsrc_create_parser.add_argument('--tls-cert', help="The absolute file name to the server certificate.")
+ dsrc_create_parser.add_argument('--tls-key', help="The absolute file name to the server certificate key.")
+ dsrc_create_parser.add_argument('--tls-reqcert', help="Request certificate strength: 'never', 'allow', 'hard'")
+ dsrc_create_parser.add_argument('--starttls', action='store_true', help="Use startTLS for connection to the server.")
+ dsrc_create_parser.add_argument('--pwdfile', help="The absolute path to a file containing the Bind DN's password.")
+ dsrc_create_parser.add_argument('--do-it', action='store_true', help="Create the file without any confirmation.")
+
+ dsrc_modify_parser = subcommands.add_parser('modify', help='Modify the .dsrc file')
+ dsrc_modify_parser.set_defaults(func=modify_dsrc)
+ dsrc_modify_parser.add_argument('--uri', nargs='?', const='', help="The URI (LDAP URL) for the Directory Server instance.")
+ dsrc_modify_parser.add_argument('--basedn', nargs='?', const='', help="The default database suffix.")
+ dsrc_modify_parser.add_argument('--binddn', nargs='?', const='', help="The default Bind DN used or authentication.")
+ dsrc_modify_parser.add_argument('--saslmech', nargs='?', const='', help="The SASL mechanism to use: PLAIN or EXTERNAL.")
+ dsrc_modify_parser.add_argument('--tls-cacertdir', nargs='?', const='', help="The directory containing the Trusted Certificate Authority certificate.")
+ dsrc_modify_parser.add_argument('--tls-cert', nargs='?', const='', help="The absolute file name to the server certificate.")
+ dsrc_modify_parser.add_argument('--tls-key', nargs='?', const='', help="The absolute file name to the server certificate key.")
+ dsrc_modify_parser.add_argument('--tls-reqcert', nargs='?', const='', help="Request certificate strength: 'never', 'allow', 'hard'")
+ dsrc_modify_parser.add_argument('--starttls', action='store_true', help="Use startTLS for connection to the server.")
+ dsrc_modify_parser.add_argument('--cancel-starttls', action='store_true', help="Do not use startTLS for connection to the server.")
+ dsrc_modify_parser.add_argument('--pwdfile', nargs='?', const='', help="The absolute path to a file containing the Bind DN's password.")
+ dsrc_modify_parser.add_argument('--do-it', action='store_true', help="Update the file without any confirmation.")
+
+ # Delete the instance from the .dsrc file
+ dsrc_delete_parser = subcommands.add_parser('delete', help='Delete instance configuration from the .dsrc file.')
+ dsrc_delete_parser.set_defaults(func=delete_dsrc)
+ dsrc_delete_parser.add_argument('--do-it', action='store_true',
+ help="Delete this instance's configuration from the .dsrc file.")
+
+ # Display .dsrc file
+ dsrc_display_parser = subcommands.add_parser('display', help='Display the contents of the .dsrc file.')
+ dsrc_display_parser.set_defaults(func=display_dsrc)
--
2.26.2

View file

@ -0,0 +1,902 @@
From 201cb1147c0a34bddbd3e5c03aecd804c47a9905 Mon Sep 17 00:00:00 2001
From: progier389 <72748589+progier389@users.noreply.github.com>
Date: Thu, 19 Nov 2020 10:21:10 +0100
Subject: [PATCH 2/2] Issue 4440 - BUG - ldifgen with --start-idx option fails
with unsupported operand (#4444)
Bug description:
Got TypeError exception when usign:
dsctl -v slapd-localhost ldifgen users --suffix
dc=example,dc=com --parent ou=people,dc=example,dc=com
--number 100000 --generic --start-idx=50
The reason is that by default python parser provides
value for numeric options:
as an integer if specified by "--option value" or
as a string if specified by "--option=value"
Fix description:
convert the numeric parameters to integer when using it.
options impacted are:
- in users subcommand: --number , --start-idx
- in mod-load subcommand: --num-users, --add-users,
--del-users, --modrdn-users, --mod-users
FYI: An alternative solution would have been to indicate the
parser that these values are an integer. But two reasons
leaded me to implement the first solution:
- first solution fix the problem for all users while the
second one fixes only dsctl command.
- first solution is easier to test:
I just added a new test file generated by a script
that duplicated existing ldifgen test, renamed the
test cases and replaced the numeric arguments by
strings.
Second solution would need to redesign the test framework
to be able to test the parser.
relates: https://github.com/389ds/389-ds-base/issues/4440
Reviewed by:
Platforms tested: F32
(cherry picked from commit 3c3e1f30cdb046a1aabb93aacebcf261a76a0892)
---
.../tests/suites/clu/dbgen_test_usan.py | 806 ++++++++++++++++++
src/lib389/lib389/cli_ctl/dbgen.py | 10 +-
src/lib389/lib389/dbgen.py | 3 +
3 files changed, 814 insertions(+), 5 deletions(-)
create mode 100644 dirsrvtests/tests/suites/clu/dbgen_test_usan.py
diff --git a/dirsrvtests/tests/suites/clu/dbgen_test_usan.py b/dirsrvtests/tests/suites/clu/dbgen_test_usan.py
new file mode 100644
index 000000000..80ff63417
--- /dev/null
+++ b/dirsrvtests/tests/suites/clu/dbgen_test_usan.py
@@ -0,0 +1,806 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2020 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+#
+import time
+
+"""
+ This file contains tests similar to dbgen_test.py
+ except that paramaters that are number are expressed as string
+ (to mimic the parameters parser default behavior which returns an
+ int when parsing "option value" and a string when parsing "option=value"
+ This file has been generated by usign:
+sed '
+9r z1
+s/ test_/ test_usan/
+/args.*= [0-9]/s,[0-9]*$,"&",
+/:id:/s/.$/1/
+' dbgen_test.py > dbgen_test_usan.py
+ ( with z1 file containing this comment )
+"""
+
+
+
+import subprocess
+import pytest
+
+from lib389.cli_ctl.dbgen import *
+from lib389.cos import CosClassicDefinitions, CosPointerDefinitions, CosIndirectDefinitions, CosTemplates
+from lib389.idm.account import Accounts
+from lib389.idm.group import Groups
+from lib389.idm.role import ManagedRoles, FilteredRoles, NestedRoles
+from lib389.tasks import *
+from lib389.utils import *
+from lib389.topologies import topology_st
+from lib389.cli_base import FakeArgs
+
+pytestmark = pytest.mark.tier0
+
+LOG_FILE = '/tmp/dbgen.log'
+logging.getLogger(__name__).setLevel(logging.DEBUG)
+log = logging.getLogger(__name__)
+
+
+@pytest.fixture(scope="function")
+def set_log_file_and_ldif(topology_st, request):
+ global ldif_file
+ ldif_file = get_ldif_dir(topology_st.standalone) + '/created.ldif'
+
+ fh = logging.FileHandler(LOG_FILE)
+ fh.setLevel(logging.DEBUG)
+ log.addHandler(fh)
+
+ def fin():
+ log.info('Delete files')
+ os.remove(LOG_FILE)
+ os.remove(ldif_file)
+
+ request.addfinalizer(fin)
+
+
+def run_offline_import(instance, ldif_file):
+ log.info('Stopping the server and running offline import...')
+ instance.stop()
+ assert instance.ldif2db(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], encrypt=None, excludeSuffixes=None,
+ import_file=ldif_file)
+ instance.start()
+
+
+def run_ldapmodify_from_file(instance, ldif_file, output_to_check=None):
+ LDAP_MOD = '/usr/bin/ldapmodify'
+ log.info('Add entries from ldif file with ldapmodify')
+ result = subprocess.check_output([LDAP_MOD, '-cx', '-D', DN_DM, '-w', PASSWORD,
+ '-h', instance.host, '-p', str(instance.port), '-af', ldif_file])
+ if output_to_check is not None:
+ assert output_to_check in ensure_str(result)
+
+
+def check_value_in_log_and_reset(content_list):
+ with open(LOG_FILE, 'r+') as f:
+ file_content = f.read()
+ log.info('Check if content is present in output')
+ for item in content_list:
+ assert item in file_content
+
+ log.info('Reset log file for next test')
+ f.truncate(0)
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_users(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create ldif with users
+
+ :id: 426b5b94-9923-454d-a736-7e71ca985e91
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with users
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.suffix = DEFAULT_SUFFIX
+ args.parent = 'ou=people,dc=example,dc=com'
+ args.number = "1000"
+ args.rdn_cn = False
+ args.generic = True
+ args.start_idx = "50"
+ args.localize = False
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'suffix={}'.format(args.suffix),
+ 'parent={}'.format(args.parent),
+ 'number={}'.format(args.number),
+ 'rdn-cn={}'.format(args.rdn_cn),
+ 'generic={}'.format(args.generic),
+ 'start-idx={}'.format(args.start_idx),
+ 'localize={}'.format(args.localize),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create users ldif')
+ dbgen_create_users(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ log.info('Get number of accounts before import')
+ accounts = Accounts(standalone, DEFAULT_SUFFIX)
+ count_account = len(accounts.filter('(uid=*)'))
+
+ run_offline_import(standalone, ldif_file)
+
+ log.info('Check that accounts are imported')
+ assert len(accounts.filter('(uid=*)')) > count_account
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_groups(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create ldif with group
+
+ :id: 97207413-9a93-4065-a5ec-63aa93801a31
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with group
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+ LDAP_RESULT = 'adding new entry "cn=myGroup-1,ou=groups,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.NAME = 'myGroup'
+ args.parent = 'ou=groups,dc=example,dc=com'
+ args.suffix = DEFAULT_SUFFIX
+ args.number = "1"
+ args.num_members = "1000"
+ args.create_members = True
+ args.member_attr = 'uniquemember'
+ args.member_parent = 'ou=people,dc=example,dc=com'
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'number={}'.format(args.number),
+ 'suffix={}'.format(args.suffix),
+ 'num-members={}'.format(args.num_members),
+ 'create-members={}'.format(args.create_members),
+ 'member-parent={}'.format(args.member_parent),
+ 'member-attr={}'.format(args.member_attr),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create group ldif')
+ dbgen_create_groups(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ log.info('Get number of accounts before import')
+ accounts = Accounts(standalone, DEFAULT_SUFFIX)
+ count_account = len(accounts.filter('(uid=*)'))
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ # ldapmodify will complain about already existing parent which causes subprocess to return exit code != 0
+ with pytest.raises(subprocess.CalledProcessError):
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that accounts are imported')
+ assert len(accounts.filter('(uid=*)')) > count_account
+
+ log.info('Check that group is imported')
+ groups = Groups(standalone, DEFAULT_SUFFIX)
+ assert groups.exists(args.NAME + '-1')
+ new_group = groups.get(args.NAME + '-1')
+ new_group.present('uniquemember', 'uid=group_entry1-0152,ou=people,dc=example,dc=com')
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_cos_classic(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a COS definition
+
+ :id: 8557f994-8a91-4f8a-86f6-9cb826a0b8f1
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with classic COS definition
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Postal_Def,ou=cos definitions,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.type = 'classic'
+ args.NAME = 'My_Postal_Def'
+ args.parent = 'ou=cos definitions,dc=example,dc=com'
+ args.create_parent = True
+ args.cos_specifier = 'businessCategory'
+ args.cos_attr = ['postalcode', 'telephonenumber']
+ args.cos_template = 'cn=sales,cn=classicCoS,dc=example,dc=com'
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'type={}'.format(args.type),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'cos-specifier={}'.format(args.cos_specifier),
+ 'cos-template={}'.format(args.cos_template),
+ 'cos-attr={}'.format(args.cos_attr),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create COS definition ldif')
+ dbgen_create_cos_def(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that COS definition is imported')
+ cos_def = CosClassicDefinitions(standalone, args.parent)
+ assert cos_def.exists(args.NAME)
+ new_cos = cos_def.get(args.NAME)
+ assert new_cos.present('cosTemplateDN', args.cos_template)
+ assert new_cos.present('cosSpecifier', args.cos_specifier)
+ assert new_cos.present('cosAttribute', args.cos_attr[0])
+ assert new_cos.present('cosAttribute', args.cos_attr[1])
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_cos_pointer(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a COS definition
+
+ :id: 6b26ca6d-226a-4f93-925e-faf95cc20211
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with pointer COS definition
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Postal_Def_pointer,ou=cos pointer definitions,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.type = 'pointer'
+ args.NAME = 'My_Postal_Def_pointer'
+ args.parent = 'ou=cos pointer definitions,dc=example,dc=com'
+ args.create_parent = True
+ args.cos_specifier = None
+ args.cos_attr = ['postalcode', 'telephonenumber']
+ args.cos_template = 'cn=sales,cn=pointerCoS,dc=example,dc=com'
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'type={}'.format(args.type),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'cos-template={}'.format(args.cos_template),
+ 'cos-attr={}'.format(args.cos_attr),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create COS definition ldif')
+ dbgen_create_cos_def(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that COS definition is imported')
+ cos_def = CosPointerDefinitions(standalone, args.parent)
+ assert cos_def.exists(args.NAME)
+ new_cos = cos_def.get(args.NAME)
+ assert new_cos.present('cosTemplateDN', args.cos_template)
+ assert new_cos.present('cosAttribute', args.cos_attr[0])
+ assert new_cos.present('cosAttribute', args.cos_attr[1])
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_cos_indirect(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a COS definition
+
+ :id: ab4b799e-e801-432a-a61d-badad2628201
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with indirect COS definition
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Postal_Def_indirect,ou=cos indirect definitions,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.type = 'indirect'
+ args.NAME = 'My_Postal_Def_indirect'
+ args.parent = 'ou=cos indirect definitions,dc=example,dc=com'
+ args.create_parent = True
+ args.cos_specifier = 'businessCategory'
+ args.cos_attr = ['postalcode', 'telephonenumber']
+ args.cos_template = None
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'type={}'.format(args.type),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'cos-specifier={}'.format(args.cos_specifier),
+ 'cos-attr={}'.format(args.cos_attr),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create COS definition ldif')
+ dbgen_create_cos_def(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that COS definition is imported')
+ cos_def = CosIndirectDefinitions(standalone, args.parent)
+ assert cos_def.exists(args.NAME)
+ new_cos = cos_def.get(args.NAME)
+ assert new_cos.present('cosIndirectSpecifier', args.cos_specifier)
+ assert new_cos.present('cosAttribute', args.cos_attr[0])
+ assert new_cos.present('cosAttribute', args.cos_attr[1])
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_cos_template(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a COS template
+
+ :id: 544017c7-4a82-4e7d-a047-00b68a28e071
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with COS template
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Template,ou=cos templates,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.NAME = 'My_Template'
+ args.parent = 'ou=cos templates,dc=example,dc=com'
+ args.create_parent = True
+ args.cos_priority = "1"
+ args.cos_attr_val = 'postalcode:12345'
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'cos-priority={}'.format(args.cos_priority),
+ 'cos-attr-val={}'.format(args.cos_attr_val),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create COS template ldif')
+ dbgen_create_cos_tmp(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that COS template is imported')
+ cos_temp = CosTemplates(standalone, args.parent)
+ assert cos_temp.exists(args.NAME)
+ new_cos = cos_temp.get(args.NAME)
+ assert new_cos.present('cosPriority', str(args.cos_priority))
+ assert new_cos.present('postalcode', '12345')
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_managed_role(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a managed role
+
+ :id: 10e77b41-0bc1-4ad5-a144-2c5107455b91
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with managed role
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Managed_Role,ou=managed roles,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+
+ args.NAME = 'My_Managed_Role'
+ args.parent = 'ou=managed roles,dc=example,dc=com'
+ args.create_parent = True
+ args.type = 'managed'
+ args.filter = None
+ args.role_dn = None
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'type={}'.format(args.type),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create managed role ldif')
+ dbgen_create_role(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that managed role is imported')
+ roles = ManagedRoles(standalone, DEFAULT_SUFFIX)
+ assert roles.exists(args.NAME)
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_filtered_role(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a filtered role
+
+ :id: cb3c8ea8-4234-40e2-8810-fb6a25973921
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with filtered role
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Filtered_Role,ou=filtered roles,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+
+ args.NAME = 'My_Filtered_Role'
+ args.parent = 'ou=filtered roles,dc=example,dc=com'
+ args.create_parent = True
+ args.type = 'filtered'
+ args.filter = '"objectclass=posixAccount"'
+ args.role_dn = None
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'type={}'.format(args.type),
+ 'filter={}'.format(args.filter),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create filtered role ldif')
+ dbgen_create_role(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that filtered role is imported')
+ roles = FilteredRoles(standalone, DEFAULT_SUFFIX)
+ assert roles.exists(args.NAME)
+ new_role = roles.get(args.NAME)
+ assert new_role.present('nsRoleFilter', args.filter)
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_nested_role(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create a nested role
+
+ :id: 97fff0a8-3103-4adb-be04-2799ff58d8f1
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate ldif with nested role
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ LDAP_RESULT = 'adding new entry "cn=My_Nested_Role,ou=nested roles,dc=example,dc=com"'
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.NAME = 'My_Nested_Role'
+ args.parent = 'ou=nested roles,dc=example,dc=com'
+ args.create_parent = True
+ args.type = 'nested'
+ args.filter = None
+ args.role_dn = ['cn=some_role,ou=roles,dc=example,dc=com']
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'NAME={}'.format(args.NAME),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'type={}'.format(args.type),
+ 'role-dn={}'.format(args.role_dn),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create nested role ldif')
+ dbgen_create_role(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
+
+ log.info('Check that nested role is imported')
+ roles = NestedRoles(standalone, DEFAULT_SUFFIX)
+ assert roles.exists(args.NAME)
+ new_role = roles.get(args.NAME)
+ assert new_role.present('nsRoleDN', args.role_dn[0])
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_mod_ldif_mixed(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create mixed modification ldif
+
+ :id: 4a2e0901-2b48-452e-a4a0-507735132c81
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate modification ldif
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.parent = DEFAULT_SUFFIX
+ args.create_users = True
+ args.delete_users = True
+ args.create_parent = False
+ args.num_users = "1000"
+ args.add_users = "100"
+ args.del_users = "999"
+ args.modrdn_users = "100"
+ args.mod_users = "10"
+ args.mod_attrs = ['cn', 'uid', 'sn']
+ args.randomize = False
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'create-users={}'.format(args.create_users),
+ 'parent={}'.format(args.parent),
+ 'create-parent={}'.format(args.create_parent),
+ 'delete-users={}'.format(args.delete_users),
+ 'num-users={}'.format(args.num_users),
+ 'add-users={}'.format(args.add_users),
+ 'del-users={}'.format(args.del_users),
+ 'modrdn-users={}'.format(args.modrdn_users),
+ 'mod-users={}'.format(args.mod_users),
+ 'mod-attrs={}'.format(args.mod_attrs),
+ 'randomize={}'.format(args.randomize),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created LDIF file: {}'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create modification ldif')
+ dbgen_create_mods(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ log.info('Get number of accounts before import')
+ accounts = Accounts(standalone, DEFAULT_SUFFIX)
+ count_account = len(accounts.filter('(uid=*)'))
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ # ldapmodify will complain about a lot of changes done which causes subprocess to return exit code != 0
+ with pytest.raises(subprocess.CalledProcessError):
+ run_ldapmodify_from_file(standalone, ldif_file)
+
+ log.info('Check that some accounts are imported')
+ assert len(accounts.filter('(uid=*)')) > count_account
+
+
+@pytest.mark.ds50545
+@pytest.mark.bz1798394
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
+def test_usandsconf_dbgen_nested_ldif(topology_st, set_log_file_and_ldif):
+ """Test ldifgen (formerly dbgen) tool to create nested ldif
+
+ :id: 9c281c28-4169-45e0-8c07-c5502d9a7581
+ :setup: Standalone instance
+ :steps:
+ 1. Create DS instance
+ 2. Run ldifgen to generate nested ldif
+ 3. Import generated ldif to database
+ 4. Check it was properly imported
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Success
+ """
+
+ standalone = topology_st.standalone
+
+ args = FakeArgs()
+ args.suffix = DEFAULT_SUFFIX
+ args.node_limit = "100"
+ args.num_users = "600"
+ args.ldif_file = ldif_file
+
+ content_list = ['Generating LDIF with the following options:',
+ 'suffix={}'.format(args.suffix),
+ 'node-limit={}'.format(args.node_limit),
+ 'num-users={}'.format(args.num_users),
+ 'ldif-file={}'.format(args.ldif_file),
+ 'Writing LDIF',
+ 'Successfully created nested LDIF file ({}) containing 6 nodes/subtrees'.format(args.ldif_file)]
+
+ log.info('Run ldifgen to create nested ldif')
+ dbgen_create_nested(standalone, log, args)
+
+ log.info('Check if file exists')
+ assert os.path.exists(ldif_file)
+
+ check_value_in_log_and_reset(content_list)
+
+ log.info('Get number of accounts before import')
+ accounts = Accounts(standalone, DEFAULT_SUFFIX)
+ count_account = len(accounts.filter('(uid=*)'))
+ count_ou = len(accounts.filter('(ou=*)'))
+
+ # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
+ # ldapmodify will complain about already existing suffix which causes subprocess to return exit code != 0
+ with pytest.raises(subprocess.CalledProcessError):
+ run_ldapmodify_from_file(standalone, ldif_file)
+
+ standalone.restart()
+
+ log.info('Check that accounts are imported')
+ assert len(accounts.filter('(uid=*)')) > count_account
+ assert len(accounts.filter('(ou=*)')) > count_ou
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
diff --git a/src/lib389/lib389/cli_ctl/dbgen.py b/src/lib389/lib389/cli_ctl/dbgen.py
index 7bc3892ba..058342fb1 100644
--- a/src/lib389/lib389/cli_ctl/dbgen.py
+++ b/src/lib389/lib389/cli_ctl/dbgen.py
@@ -451,13 +451,13 @@ def dbgen_create_mods(inst, log, args):
props = {
"createUsers": args.create_users,
"deleteUsers": args.delete_users,
- "numUsers": args.num_users,
+ "numUsers": int(args.num_users),
"parent": args.parent,
"createParent": args.create_parent,
- "addUsers": args.add_users,
- "delUsers": args.del_users,
- "modrdnUsers": args.modrdn_users,
- "modUsers": args.mod_users,
+ "addUsers": int(args.add_users),
+ "delUsers": int(args.del_users),
+ "modrdnUsers": int(args.modrdn_users),
+ "modUsers": int(args.mod_users),
"random": args.randomize,
"modAttrs": args.mod_attrs
}
diff --git a/src/lib389/lib389/dbgen.py b/src/lib389/lib389/dbgen.py
index 6273781a2..10fb200f7 100644
--- a/src/lib389/lib389/dbgen.py
+++ b/src/lib389/lib389/dbgen.py
@@ -220,6 +220,9 @@ def dbgen_users(instance, number, ldif_file, suffix, generic=False, entry_name="
"""
Generate an LDIF of randomly named entries
"""
+ # Lets insure that integer parameters are not string
+ number=int(number)
+ startIdx=int(startIdx)
familyname_file = os.path.join(instance.ds_paths.data_dir, 'dirsrv/data/dbgen-FamilyNames')
givename_file = os.path.join(instance.ds_paths.data_dir, 'dirsrv/data/dbgen-GivenNames')
familynames = []
--
2.26.2

View file

@ -45,7 +45,7 @@ ExcludeArch: i686
Summary: 389 Directory Server (base)
Name: 389-ds-base
Version: 1.4.3.16
Release: %{?relprefix}3%{?prerel}%{?dist}
Release: %{?relprefix}4%{?prerel}%{?dist}
License: GPLv3+
URL: https://www.port389.org
Group: System Environment/Daemons
@ -181,6 +181,9 @@ Patch04: 0004-Ticket-50933-Update-2307compat.ldif.patch
Patch05: 0005-Issue-50933-Fix-OID-change-between-10rfc2307-and-10r.patch
Patch06: 0006-Ticket-51131-improve-mutex-alloc-in-conntable.patch
Patch07: 0007-Issue-4297-2nd-fix-for-on-ADD-replication-URP-issue-.patch
Patch08: 0008-Issue-3657-Add-options-to-dsctl-for-dsrc-file.patch
Patch09: 0009-Issue-4440-BUG-ldifgen-with-start-idx-option-fails-w.patch
%description
389 Directory Server is an LDAPv3 compliant server. The base package includes
@ -798,6 +801,12 @@ exit 0
%doc README.md
%changelog
* Thu Dec 3 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.16-4
- Bump version to 1.4.3.16-4
- Resolves: Bug 1843517 - Using ldifgen with --start-idx option fails with unsupported operand
- Resolves: Bug 1801086 - [RFE] Generate dsrc file using dsconf
- Resolves: Bug 1843838 - heap-use-after-free in slapi_be_getsuffix
* Wed Nov 25 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.16-3
- Bump version to 1.4.3.16-3
- Resolves: Bug 1859219 - rfc2307 and rfc2307bis compat schema