### Common test imports and setup Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Python code snippet showing common imports and logging setup for tests. ```python import pytest import ldap import logging import os from lib389.topologies import topology_st as topo from lib389._constants import DEFAULT_SUFFIX, PASSWORD from lib389.idm.user import UserAccounts, UserAccount from lib389.plugins import MemberOfPlugin from lib389.utils import ds_supports_new_changelog pytestmark = pytest.mark.tier1 DEBUGGING = os.getenv("DEBUGGING", default=False) if DEBUGGING: logging.getLogger(__name__).setLevel(logging.DEBUG) else: logging.getLogger(__name__).setLevel(logging.INFO) log = logging.getLogger(__name__) ``` -------------------------------- ### Install lib389 via pip Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/README.md Use this command to install the library. Ensure the version matches your 389 Directory Server instance. ```bash pip3 install lib389==3.1.2 ``` -------------------------------- ### Create Topology Example Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/replica.md Example of creating a basic replica topology using the create_topology function. ```python from test389.topologies import create_topology topology = create_topology({ ReplicaRole.SUPPLIER: 2, ReplicaRole.CONSUMER: 2 }) ``` -------------------------------- ### Clone and Configure Repository Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Initial setup commands to clone the repository and add a personal fork as a remote. ```bash git clone git@github.com:389ds/389-ds-base.git git remote add myfork git@github.com:USERNAME/389-ds-base.git ``` -------------------------------- ### Start, Stop, and Restart Directory Server Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Control the lifecycle of the directory server instance. Use start(), stop(), and restart() methods with an optional timeout. ```python # Start, Stop, and Restart the Server standalone.start(timeout=10) standalone.stop(timeout=10) standalone.restart(timeout=10) ``` -------------------------------- ### Test docstring format example Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Python code snippet illustrating the required structured docstring format for test functions, including fields like :id:, :setup:, :steps:, and :expectedresults:. ```python def test_example_feature(topo): """Short description of what the test verifies :id: :setup: Describe the test setup (e.g. "Standalone instance" or "Two supplier replication") :steps: 1. First action 2. Second action 3. Third action :expectedresults: 1. Expected outcome of step 1 2. Expected outcome of step 2 3. Expected outcome of step 3 """ ... ``` -------------------------------- ### Define Test Case Docstring Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Example of the required docstring format for test cases, including ID, setup, steps, and expected results. ```python """Test if member is automatically added to the group :id: 38621a51-03bc-4fba-93ef-7e525df87c5d :setup: Standalone instance, enabled Auto Membership Plugin :steps: 1. Create a user 2. Assert that the user is member of the group :expectedresults: 1. Should be success 2. Should be success """ ``` -------------------------------- ### Install Sanitizer Packages Source: https://github.com/389ds/389-ds-base/blob/main/dirsrvtests/sanitizers/README.md Required libraries for LSan and TSan functionality. ```bash dnf install liblsan # for --sanitizer=lsan dnf install libtsan # for --sanitizer=tsan ``` -------------------------------- ### Import test topology fixtures Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Python code snippets demonstrating how to import various test topology fixtures from lib389.topologies. ```python from lib389.topologies import topology_st as topo # Standalone ``` ```python from lib389.topologies import topology_m2 as topo # 2 suppliers ``` ```python from lib389.topologies import topology_m3 as topo_m3 # 3 suppliers ``` ```python from lib389.topologies import topology_m4 as topo_m4 # 4 suppliers ``` ```python from lib389.topologies import topology_m2c2 as topo_m2c2 # 2 suppliers + 2 consumers ``` -------------------------------- ### Build and verify Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/contributing.md Builds the 389 Directory Server from source, including debug options and tests, and installs it. ```bash autoreconf -fiv ./configure --enable-debug --with-openldap --enable-cmocka make make lib389 sudo make install sudo make lib389-install make check ``` -------------------------------- ### Run C Unit Tests Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Command to run C unit tests using make check. ```bash make check ``` -------------------------------- ### Autotools Build Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/building.md Commands to configure, build, and install the project using Autotools. ```bash autoreconf -fiv ./configure --enable-debug --with-openldap --enable-cmocka make make lib389 sudo make install sudo make lib389-install ``` -------------------------------- ### Generate and Hash Password with lib389 Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/passwd.md Demonstrates how to generate a raw secure password and then hash it using a specified scheme and binary directory. Ensure lib389 is installed and the bin_dir path is correct. ```python from lib389.passwd import password_hash, password_generate bindir = standalone.ds_paths.bin_dir PWSCHEMES = [ 'SHA1', 'SHA256', 'SHA512', 'SSHA', 'SSHA256', 'SSHA512', 'PBKDF2_SHA256', 'PBKDF2-SHA256', ] # Generate password raw_secure_password = password_generate() # Encrypt the password # default scheme is 'SSHA512' secure_password = password_hash(raw_secure_password, scheme='SSHA256', bin_dir=bindir) ``` -------------------------------- ### Minimal Rust Plugin Example Source: https://github.com/389ds/389-ds-base/blob/main/src/slapi_r_plugin/README.md A basic Rust plugin demonstrating the structure required for 389 Directory Server plugins, including trait implementation and error handling. ```rust #[macro_use] extern crate slapi_r_plugin; use slapi_r_plugin::prelude::*; struct NewPlugin; slapi_r_plugin_hooks!(plugin_name, NewPlugin); impl SlapiPlugin3 for NewPlugin { fn start(_pb: &mut PblockRef) -> Result<(), PluginError> { log_error!(ErrorLevel::Trace, "plugin start"); Ok(()) } fn close(_pb: &mut PblockRef) -> Result<(), PluginError> { log_error!(ErrorLevel::Trace, "plugin close"); Ok(()) } fn has_betxn_pre_add() -> bool { true } fn betxn_pre_add(pb: &mut PblockRef) -> Result<(), PluginError> { let mut e = pb.get_op_add_entryref().map_err(|_| PluginError::Pblock)?; let sdn = e.get_sdnref(); log_error!(ErrorLevel::Trace, "betxn_pre_add -> {:?}", sdn); Ok(()) } } ``` -------------------------------- ### Commit Message Format Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Example of a properly formatted commit message following project guidelines. ```text Issue 48085 - Expand the repl acceptance test suite Description: Add 6 more test cases to the replication test suite as a part of the TET to pytest porting initiative. Increase the number of seconds we wait before the results check. https://github.com/389ds/389-ds-base/issues/1416 Reviewed by: ? ``` -------------------------------- ### Debug C Unit Tests Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Command to debug C unit tests using gdb. ```bash libtool --mode=execute gdb /path/to/test_binary ``` -------------------------------- ### Define Test Function Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Example of a test function signature accepting fixtures as arguments. ```python def test_search_limits_fail(topology, rdn_write_setup): ``` -------------------------------- ### C Program Arguments Example Source: https://github.com/389ds/389-ds-base/blob/main/rfcs/examples/template-bare-06.txt This C code snippet demonstrates how to access and print program arguments passed to a C program. It iterates through the argument count and displays each argument. ```c /**** an example C program */ #include void main(int argc, char *argv[]) { int i; printf("program arguments are:\n"); for (i = 0; i < argc; i++) { printf("%d: \"%s\"\n", i, argv[i]); } exit(0); } /* main */ /* end of file */ ``` -------------------------------- ### Run a specific Python integration test suite Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Command to run a specific suite of Python integration tests using pytest. ```bash sudo py.test -s dirsrvtests/tests/suites/basic/ ``` -------------------------------- ### Manage directory server indexes with lib389 Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/indexes.md Demonstrates creating, retrieving, updating, and deleting indexes. Requires an initialized standalone instance. ```python from lib389.index import Indexes indexes = Indexes(standalone) # Create a default index index = indexes.create(properties={ 'cn': 'modifytimestamp', 'nsSystemIndex': 'false', 'nsIndexType': 'eq' }) # Get an index by DN index = indexes.get(dn=YOUR_INDEX_DN) # Set index types index.replace('nsIndexType', ['eq', 'sub', 'pres']) # Set matching rules (matching_rules - variable with matching rules) index.replace('caseIgnoreOrderingMatch', matching_rules) default_index_list = indexes.list() found = False for i in default_index_list: if i.dn.startswith('cn=modifytimestamp'): found = True assert found index.delete() default_index_list = indexes.list() found = False for i in default_index_list: if i.dn.startswith('cn=modifytimestamp'): found = True assert not found ``` -------------------------------- ### Enable and Disable Plugins with Python Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/plugin.md Demonstrates basic plugin management using the `Plugins` interface. Ensure the `standalone` object is initialized before use. ```python from lib389.plugin import Plugins, ACLPlugin from lib389._constants import PLUGIN_ACL # You can just enable/disable plugins from Plugins interface plugins = Plugins(standalone) plugins.enable(PLUGIN_ACL) # Or you can first 'get' it and then work with it (make sense if your plugin is a complex one) aclplugin = ACLPlugin(standalone) aclplugin.enable() aclplugin.disable() ``` -------------------------------- ### Manage Groups and POSIX Groups with lib389 Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/group.md Demonstrates creating groups, checking membership, adding members, and removing members using the Groups and PosixGroups classes. ```python # group and groups additionaly have 'is_member', 'add_member' and 'remove_member' methods # posixgroup and posixgroups have 'check_member' and 'add_member' from lib389.idm.group import Groups from lib389.idm.posixgroup import PosixGroups groups = Groups(standalone, DEFAULT_SUFFIX) posix_groups = PosixGroups(standalone, DEFAULT_SUFFIX) group_properties = { 'cn' : 'group1', 'description' : 'testgroup' } group = groups.create(properties=group_properties) # So now you can: # Check the membership - shouldn't we make it consistent? assert(not group.is_member(testuser.dn)) assert(not posix_groups.check_member(testuser.dn)) group.add_member(testuser.dn) posix_groups.add_member(testuser.dn) # Remove member - add the method to PosixGroups too? group.remove_member(testuser.dn) group.delete(): ``` -------------------------------- ### Configure TLS Authentication for a Single Instance Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md This script demonstrates setting up TLS authentication for a standalone 389 Directory Server instance. It involves creating a user, configuring certmaps, and performing an external bind with TLS. ```python standalone.stop() # Create a user assert(standalone.nss_ssl.create_rsa_user('testuser') is True) # Get the details of where the key and crt are # {'ca': ca_path, 'key': key_path, 'crt': crt_path} tls_locs = standalone.nss_ssl.get_rsa_user('testuser') standalone.start() # Create user in the directory users = UserAccounts(standalone, DEFAULT_SUFFIX) users.create(properties={ 'uid': 'testuser', 'cn' : 'testuser', 'sn' : 'user', 'uidNumber' : '1000', 'gidNumber' : '2000', 'homeDirectory' : '/home/testuser' }) # Turn on the certmap cm = CertmapLegacy(standalone) certmaps = cm.list() certmaps['default']['DNComps'] = '' certmaps['default']['FilterComps'] = ['cn'] certmaps['default']['VerifyCert'] = 'off' cm.set(certmaps) # Restart to allow certmaps to be re-read: Note, we CAN NOT use post_open standalone.restart(post_open=False) # Now attempt a bind with TLS external conn = standalone.openConnection(saslmethod='EXTERNAL', connOnly=True, certdir=standalone.get_cert_dir(), userkey=tls_locs['key'], usercert=tls_locs['crt']) assert(conn.whoami_s() == "dn: uid=testuser,ou=People,dc=example,dc=com") ``` -------------------------------- ### Manage User Accounts with lib389 Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/user.md Demonstrates the lifecycle of a user account including creation, attribute modification, binding, and deletion. ```python # There is a basic way to work with it from lib389.idm.user import UserAccounts users = UserAccounts(standalone, DEFAULT_SUFFIX) user_properties = { 'uid': USER_NAME, 'cn' : USER_NAME, 'sn' : USER_NAME, 'userpassword' : USER_PWD, 'uidNumber' : '1000', 'gidNumber' : '2000',1 'homeDirectory' : '/home/{}'.format(USER_NAME) } testuser = users.create(properties=user_properties) # After this you can: # Get the list of them users.list() # Get some user: testuser = users.get('testuser') # or testuser = users.list()[0] # You can loop through 'for user in users:' # Set some attribute to the entry testuser.set('userPassword', 'password') # Bind as the user conn = testuser.bind('password') # It will create a new connection conn.modify_s() conn.unbind_s() # Delete testuser.delete() ``` -------------------------------- ### Define Test Fixture Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Example of a pytest fixture that sets up and tears down an entry for a test case. ```python @pytest.fixture def rdn_write_setup(topology_m2): topology_m2.ms["supplier1"].add_s(ENTRY) def fin(): topology_m2.ms["supplier1"].delete_s(ENTRY_DN) request.addfinalizer(fin) ``` -------------------------------- ### Create and Manage 389 DS Backend Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/backend.md Use this snippet to create a new backend with specified properties, generate sample entries, and then delete the backend. Ensure 'standalone' is properly initialized before use. ```python from lib389.backend import Backends backends = Backends(standalone) backend = backends.create(properties={'nsslapd-suffix': 'o=new_suffix', # mandatory 'cn': 'new_backend'}) # Create sample entries backend.create_sample_entries(version='001003006') backend.delete() ``` -------------------------------- ### Connect to 389 Directory Server Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/README.md Demonstrates establishing a connection using environment-based configuration and searching for user accounts. ```python from lib389 import DirSrv from lib389.idm.user import UserAccounts def get_ldap_config(): """Get LDAP configuration from environment variables.""" return { 'ldap_url': 'ldap://localhost:389', 'base_dn': 'dc=example,dc=com', 'bind_dn': 'cn=Directory Manager', 'bind_password': 'Password123' } def get_ldap_connection(): """Create and return a connection to the LDAP server.""" config = get_ldap_config() ds = DirSrv(verbose=True) try: ds.remote_simple_allocate( config['ldap_url'], config['bind_dn'], config['bind_password'] ) ds.open() print(f"Successfully connected to {config['ldap_url']} as {config['bind_dn']}") return ds except Exception as e: print(f"Failed to connect to LDAP server: {e}") raise def search_users_example(basedn=None): """Example function to search for users and return their details as JSON.""" config = get_ldap_config() search_basedn = basedn or config['base_dn'] connection = get_ldap_connection() if not connection: print("Could not establish LDAP connection.") return [] users = UserAccounts(connection, search_basedn) for user in users.list(): print(user.display()) print("Closing LDAP connection in search_users_example.") connection.unbind_s() if __name__ == '__main__': search_users_example() ``` -------------------------------- ### Generate unique test ID Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Python command to generate a unique UUID for test IDs. ```python python -c "import uuid; print(uuid.uuid4())" ``` -------------------------------- ### Retrieve Schema CSN and Definitions Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/schema.md Get the schema's CSN attribute or lists of all supported object classes and attribute types. ```python schema_csn = standalone.schema.get_schema_csn() objectclasses = standalone.schema.get_objectclasses() attributetypes = standalone.schema.get_attributetypes() ``` -------------------------------- ### Run Tests with Sanitizers Source: https://github.com/389ds/389-ds-base/blob/main/dirsrvtests/sanitizers/README.md Commands to initialize the host environment and execute tests with specific sanitizer configurations. ```bash # One-time host setup (as root): sudo dirsrvtests/sanitizers/setup_host.sh # Run tests with leak detection: pytest --sanitizer=lsan -xvs dirsrvtests/tests/suites/syncrepl_plugin/ # Run tests with thread sanitizer: pytest --sanitizer=tsan -xvs dirsrvtests/tests/suites/replication/ ``` -------------------------------- ### Build and Watch 389-Console UI Source: https://github.com/389ds/389-ds-base/blob/main/src/cockpit/389-console/README.md Navigate to the 389-console directory and execute this script to build the UI and continuously watch for source code changes. This allows for live updates in the browser without reinstallation. ```bash cd /home/USERNAME/source/389-ds-base/src/cockpit/389-console/ ./buildAndRun.sh ``` -------------------------------- ### Build 389 Directory Server Source: https://github.com/389ds/389-ds-base/blob/main/README.md Use these commands to build the 389 Directory Server from source. The --enable-asan option is for debugging and development purposes only. ```bash autoreconf -fiv ./configure --enable-debug --with-openldap --enable-cmocka --enable-asan make make lib389 sudo make install sudo make lib389-install ``` -------------------------------- ### Retrieve Schema Information Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/schema.md Use these functions to get the entire schema as an LDAP entry, a python-ldap SubSchema object, or a list of schema files. ```python schema = standalone.schema.get_entry() subschema = standalone.schema.get_subschema() schema_files = standalone.schema.list_files() ``` -------------------------------- ### Assign a tier marker to a test module Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Python code snippet to assign a tier marker to a test module using pytest. ```python pytestmark = pytest.mark.tier1 ``` -------------------------------- ### Create Users and Run Load Test with ldclt Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/ldclt.md Use ldclt to create a range of users with specified attributes and then run a bind load test against them. Ensure DEFAULT_SUFFIX is defined in your environment. ```python # Creates users as user. Password will be set to password # This will automatically work with the bind load test. # Template # objectClass: top # objectclass: person # objectClass: organizationalPerson # objectClass: inetorgperson # objectClass: posixAccount # objectClass: shadowAccount # sn: user[A] # cn: user[A] # givenName: user[A] # description: description [A] # userPassword: user[A] # mail: user[A]@example.com # uidNumber: 1[A] # gidNumber: 2[A] # shadowMin: 0 # shadowMax: 99999 # shadowInactive: 30 # shadowWarning: 7 # homeDirectory: /home/user[A] # loginShell: /bin/false topology.instance.ldclt.create_users('ou=People,{}'.format(DEFAULT_SUFFIX), max=1999) # Run the load test for a few rounds topology.instance.ldclt.bind_loadtest('ou=People,{}'.format(DEFAULT_SUFFIX), max=1999) ``` -------------------------------- ### Manage Changelog Entries Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/changelog.md Use these commands to create, list, and delete changelog entries. Ensure the topology module is imported and a standalone instance is available. ```default standalone = topology.standalone # Create changelog_dn = standalone.changelog.create() # List changelog_entries = standalone.changelog.list(changelogdn=changelog_dn) # Delete standalone.changelog.delete() ``` -------------------------------- ### Filter Python integration tests by tier marker Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Command to filter and run Python integration tests by a tier marker using pytest. ```bash sudo py.test -m tier0 dirsrvtests/tests/suites/ ``` -------------------------------- ### Create Cockpit Directory Source: https://github.com/389ds/389-ds-base/blob/main/src/cockpit/389-console/README.md Use this command to create the necessary directory for the cockpit plugin in the user's home directory. ```bash mkdir ~/.local/share/cockpit ``` -------------------------------- ### Update ldapu_cert_to_ldap_entry signature Source: https://github.com/389ds/389-ds-base/blob/main/lib/ldaputil/ldapu-changes.html The function signature was updated to include a basedn parameter, allowing searches to start from the server's base DN when the mapped DN is NULL. ```c int ldapu_cert_to_ldap_entry(void *cert, LDAP *ld, const char *basedn, LDAPMessage **res); ``` -------------------------------- ### Create Simple Domain Entry Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/domain.md Use this when you need to create a basic domain entry without the overhead of sample entries. The domain entry will be automatically deleted when the associated backend is deleted. ```python # After the creating a backend, sometimes you don't need a lot of entries under the created suffix # So instead of using BACKEND_SAMPLE_ENTRIES you can create simple domain entry using the next object: from lib389.idm.domain import Domain domain = Domain(standalone], 'dc=test,dc=com') domain.create(properties={'dc': 'test', 'description': 'dc=test,dc=com'}) # It will be deleted with the 'backend.delete()' ``` -------------------------------- ### Conditional skipping of tests Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Python code snippet demonstrating how to conditionally skip a test using pytest.mark.skipif, ensuring the docstring :id: remains unchanged. ```python @pytest.mark.skipif(ds_supports_new_changelog(), reason="This test is for legacy changelog") def test_legacy_changelog(topo): """Verify legacy changelog behavior :id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 :setup: Standalone instance :steps: 1. ... :expectedresults: 1. ... """ ... ``` -------------------------------- ### Create a Mapping Tree with lib389 Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/mappingtree.md Use the MappingTrees class to manually define a mapping tree. Ensure the backend is specified in the properties. ```python from lib389.mappingTree import MappingTrees mts = MappingTrees(standalone) mt = mts.create(properties={ 'cn': ["dc=newexample,dc=com",], 'nsslapd-state' : 'backend', 'nsslapd-backend' : 'someRoot', }) ``` -------------------------------- ### Run a specific Python integration test function Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/testing.md Command to run a specific test function within a Python integration test suite using pytest. ```bash sudo py.test -v dirsrvtests/tests/suites/plugins/dna_test.py::test_function_name ``` -------------------------------- ### Create Development Branch Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Command to create and switch to a new branch for feature or test development. ```bash git checkout -b new_test_suite ``` -------------------------------- ### ldapu_cert_to_ldap_entry API Change Source: https://github.com/389ds/389-ds-base/blob/main/lib/ldaputil/ldapu-changes.html The ldapu_cert_to_ldap_entry function has been updated to allow a NULL mapped DN, enabling searches to start from the LDAP server's basedn. This change facilitates the mapping of certificates from sources like Verisign without requiring plugins. ```APIDOC ## ldapu_cert_to_ldap_entry ### Description Allows for a NULL mapped DN, initiating the search from the LDAP server's basedn. This is useful for mapping certificates from sources like Verisign. ### Method N/A (Function Signature Change) ### Endpoint N/A ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example N/A ### Response #### Success Response (200) N/A #### Response Example N/A ### New Signature ```c int ldapu_cert_to_ldap_entry(void *cert, LDAP *ld, const char *basedn, LDAPMessage **res); ``` ### Configuration Example (certmap.conf) ``` certmap verisign verisign:dncomps verisign:searchcomps cn, e ``` ### Filter Example ``` (& (cn="") (mail="")) ``` ``` -------------------------------- ### Manage Replication Agreements Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/agreement.md Use these methods to configure replication links between supplier and consumer instances. Ensure the topology objects are initialized before calling these methods. ```default supplier = topology.ms["supplier1"] consumer = topology.ms["consumer1"] # Create repl_agreement = supplier.agreement.create(suffix=DEFAULT_SUFFIX, host=consumer.host, port=consumer.port) # List ents = supplier.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=consumer.host, consumer_port=consumer.port) # Delete ents = supplier.agreement.delete(suffix=DEFAULT_SUFFIX) ``` -------------------------------- ### Create OU and Service Account Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/organizationalunit.md Use this snippet to create an Organizational Unit for service accounts and then create a service account within that OU. Ensure the 'Services' OU is created before creating service accounts. ```python # Don't forget that Services requires created rdn='ou=Services' # This you can create with OrganizationalUnits from lib389.idm.organizationalunit import OrganizationalUnits from lib389.idm.services import ServiceAccounts ous = OrganizationalUnits(standalone, DEFAULT_SUFFIX) services = ServiceAccounts(standalone, DEFAULT_SUFFIX) # Create the OU for them ous.create(properties={ 'ou': 'Services', 'description': 'Computer Service accounts which request DS bind', }) # Now, we can create the services from here. service = services.create(properties={ 'cn': 'testbind', 'userPassword': 'Password1' }) conn = service.bind('Password1') conn.unbind_s() ``` -------------------------------- ### Retrieve server performance metrics Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/monitor.md Access server version and database cache hit rates using the monitor and monitorldbm objects. ```python # Monitor and MonitorLDBM are the simple DSLdapObject things. # You can use all methods from chapter above to get current server performance detail version = standalone.monitor.get_attr_val('version') dbcachehit = standalone.monitorldbm.get_attr_val('dbcachehit') ``` -------------------------------- ### Configure Certification-Based Authentication for Replication Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Use this script to set up SSLCLIENTAUTH for replication between two instances. It configures certmaps, enables TLS, and updates replication agreements. ```python from lib389.idm.services import ServiceAccounts from lib389.config import CertmapLegacy from lib389.replica import ReplicationManager, Replicas # Create the certmap before we restart for enable_tls cm_m1 = CertmapLegacy(m1) cm_m2 = CertmapLegacy(m2) # We need to configure the same maps for both certmaps = cm_m1.list() certmaps['default']['DNComps'] = None certmaps['default']['CmapLdapAttr'] = 'nsCertSubjectDN' cm_m1.set(certmaps) cm_m2.set(certmaps) [i.enable_tls() for i in topo_m2] # Create the replication dns services = ServiceAccounts(m1, DEFAULT_SUFFIX) repl_m1 = services.get('%s:%s' % (m1.host, m1.sslport)) repl_m1.set('nsCertSubjectDN', m1.get_server_tls_subject()) repl_m2 = services.get('%s:%s' % (m2.host, m2.sslport)) repl_m2.set('nsCertSubjectDN', m2.get_server_tls_subject()) # Check the replication is "done". repl = ReplicationManager(DEFAULT_SUFFIX) repl.wait_for_replication(m1, m2) # Now change the auth type replica_m1 = Replicas(m1).get(DEFAULT_SUFFIX) agmt_m1 = replica_m1.get_agreements().list()[0] agmt_m1.replace_many( ('nsDS5ReplicaBindMethod', 'SSLCLIENTAUTH'), ('nsDS5ReplicaTransportInfo', 'SSL'), ('nsDS5ReplicaPort', '%s' % m2.sslport), ) agmt_m1.remove_all('nsDS5ReplicaBindDN') replica_m2 = Replicas(m2).get(DEFAULT_SUFFIX) agmt_m2 = replica_m2.get_agreements().list()[0] agmt_m2.replace_many( ('nsDS5ReplicaBindMethod', 'SSLCLIENTAUTH'), ('nsDS5ReplicaTransportInfo', 'SSL'), ('nsDS5ReplicaPort', '%s' % m1.sslport), ) agmt_m2.remove_all('nsDS5ReplicaBindDN') repl.test_replication_topology(topo_m2) ``` -------------------------------- ### Manage 389 Directory Server Tasks Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/task.md Demonstrates how to instantiate a Task object, monitor its status, and execute various administrative operations via the standalone tasks interface. ```python from lib389.tasks import Task newtask = Task(instance, dn) # Should we create Tasks and put the precious to TasksLegacy? newtask.create(rdn, properties, basedn) # Check if the task is complete assert(newtask.is_complete()) # Check task's exit code if task is complete, else None if newtask.is_complete(): exit_code = newtask.get_exit_code() # Wait until task is complete newtask.wait() # If True, waits for the completion of the task before to return args = {TASK_WAIT: True} # Some tasks ca be found only under old object. You can access them with this: standalone.tasks.importLDIF(DEFAULT_SUFFIX, path_ro_ldif, args) standalone.tasks.exportLDIF(DEFAULT_SUFFIX, benamebase=None, output_file=path_to_ldif, args) standalone.tasks.db2bak(backup_dir, args) standalone.tasks.bak2db(backup_dir, args) standalone.tasks.reindex(suffix=None, benamebase=None, attrname=None, args) standalone.tasks.fixupMemberOf(suffix=None, benamebase=None, filt=None, args) standalone.tasks.fixupTombstones(bename=None, args) standalone.tasks.automemberRebuild(suffix=DEFAULT_SUFFIX, scope='sub', filterstr='objectclass=top', args) standalone.tasks.automemberExport(suffix=DEFAULT_SUFFIX, scope='sub', fstr='objectclass=top', ldif_out=None, args) standalone.tasks.automemberMap(ldif_in=None, ldif_out=None, args) standalone.tasks.fixupLinkedAttrs(linkdn=None, args) standalone.tasks.schemaReload(schemadir=None, args) standalone.tasks.fixupWinsyncMembers(suffix=DEFAULT_SUFFIX, fstr='objectclass=top', args) standalone.tasks.syntaxValidate(suffix=DEFAULT_SUFFIX, fstr='objectclass=top', args) standalone.tasks.usnTombstoneCleanup(suffix=DEFAULT_SUFFIX, bename=None, maxusn_to_delete=None, args) standalone.tasks.sysconfigReload(configfile=None, logchanges=None, args) standalone.tasks.cleanAllRUV(suffix=None, replicaid=None, force=None, args) standalone.tasks.abortCleanAllRUV(suffix=None, replicaid=None, certify=None, args) standalone.tasks.upgradeDB(nsArchiveDir=None, nsDatabaseType=None, nsForceToReindex=None, args) ``` -------------------------------- ### Troubleshoot Sanitizer Reports Source: https://github.com/389ds/389-ds-base/blob/main/dirsrvtests/sanitizers/README.md Commands to verify SELinux status and sysctl settings when reports are missing. ```bash ausearch -m avc -ts recent | grep dirsrv # look for ptrace/execmem denials semodule -l | grep ds_sanitizer # policy module loaded? sysctl fs.suid_dumpable # must be 1 sysctl kernel.yama.ptrace_scope # must be 0 ``` -------------------------------- ### Replication Management and Verification Utilities Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/repltools.md Use these methods to verify CSN synchronization, generate convergence reports, and manage replication credentials across multiple DirSrv instances. ```python from lib389.repltools import ReplTools # Gather all the CSN strings from the access and verify all of those CSNs exist on all the other replicas. # dirsrv_replicas - a list of DirSrv objects. The list must begin with supplier replicas # ignoreCSNs - an optional string of csns to be ignored # if the caller knows that some csns can differ eg.: '57e39e72000000020000|vucsn-57e39e76000000030000' ReplTools.checkCSNs([supplier1, supplier2], ignoreCSNs=None) # Find and measure the convergence of entries from a replica, and # print a report on how fast all the "ops" replicated to the other replicas. # suffix - Replicated suffix # ops - A list of "operations" to search for in the access logs # replica - Dirsrv object where the entries originated # all_replicas - A list of Dirsrv replicas # It returns - The longest time in seconds for an operation to fully converge longest_time = ReplTools.replConvReport(DEFAULT_SUFFIX, ops, supplier1, [supplier1, supplier2]) # Take a list of DirSrv Objects and check to see if all of the present # replication agreements are idle for a particular backend assert(ReplTools.replIdle([supplier1, supplier2], suffix=DEFAULT_SUFFIX)) defaultProperties = { REPLICATION_BIND_DN: "cn=replication manager,cn=config", REPLICATION_BIND_PW # Create an entry that will be used to bind as replication manager ReplTools.createReplManager(standalone, repl_manager_dn=defaultProperties[REPLICATION_BIND_DN], repl_manager_pw=defaultProperties[REPLICATION_BIND_PW]) ``` -------------------------------- ### Execute CLI tools via Cockpit Source: https://github.com/389ds/389-ds-base/blob/main/src/cockpit/389-console/README.md Uses the cockpit.spawn API to execute lib389 CLI tools, expecting JSON output for parsing in the UI. ```javascript cockpit.spawn('/usr/bin/dsconf', '-z', '-n') ``` -------------------------------- ### Commit and Push Changes Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Commands to stage, commit, and push changes to the forked repository. ```bash git add ./dirsrvtests/tests/suites/basic/basic_test.py git commit git push myfork ``` -------------------------------- ### Test 389 Directory Server Source: https://github.com/389ds/389-ds-base/blob/main/README.md Run the test suite for the 389 Directory Server using 'make check' and py.test. Ensure libtool is available for debugging test failures. ```bash make check ``` ```bash sudo py.test -s 389-ds-base/dirsrvtests/tests/suites/basic/ ``` ```bash libtool --mode=execute gdb /home/william/build/ds/test_slapd ``` -------------------------------- ### RPM Build Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/building.md Command to create distribution tarballs and RPM packages. ```bash make -f rpm.mk dist-bz2 rpms ``` -------------------------------- ### Manage DSE LDIF attributes with lib389 Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/dseldif.md Use the DSEldif class to perform CRUD operations on configuration attributes. Requires an initialized topology instance. ```python from lib389.dseldif import DSEldif dse_ldif = DSEldif(topo.standalone) # Get a list of attribute values under a given entry config_cn = dse_ldif.get(DN_CONFIG, 'cn') # Add an attribute under a given entry dse_ldif.add(DN_CONFIG, 'someattr', 'someattr_value') # Replace attribute values with a new one under a given entry. It will remove all previous 'someattr' values dse_ldif.replace(DN_CONFIG, 'someattr', 'someattr_value') # Delete attributes under a given entry dse_ldif.delete(DN_CONFIG, 'someattr') dse_ldif.delete(DN_CONFIG, 'someattr', 'someattr_value') ``` -------------------------------- ### Perform Simple Bind Operations Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Authenticate to the directory server using simple bind. This includes anonymous binds and binding as a specific user or the Directory Manager. ```python # Anonymous bind bind_dn = "" bind_pwd = "" # Bind as our test entry bind_dn = USER_DN bind_pwd = "password" # Bind as Directory Manager bind_dn = DN_DM bind_pwd = 1 standalone.simple_bind_s(bind_dn, bind_pwd) ``` -------------------------------- ### Manage 389 Directory Server Configuration Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/config.md Use these methods to modify configuration attributes, toggle logging services, and adjust log levels for a standalone instance. ```python # Set config attribute: standalone.config.set('passwordStorageScheme', 'SSHA') # Reset config attribute (by deleting it): standalone.config.reset('passwordStorageScheme') # Enable/disable logs (error, access, audit): standalone.config.enable_log('error') standalone.config.disable_log('access') # Set loglevel for errors log. # If 'update' set to True, it will add the 'vals' to existing values in the loglevel attribute standalone.config.loglevel(vals=(LOG_DEFAULT,), service='error', update=False) # You can get log levels from lib389._constants (LOG_TRACE, LOG_TRACE_PACKETS, LOG_TRACE_HEAVY, LOG_CONNECT, LOG_PACKET, LOG_SEARCH_FILTER, LOG_CONFIG_PARSER, LOG_ACL, LOG_ENTRY_PARSER, LOG_HOUSEKEEPING, LOG_REPLICA, LOG_DEFAULT, LOG_CACHE, LOG_PLUGIN, LOG_MICROSECONDS, LOG_ACL_SUMMARY) = [1 << x for x in (list(range(8)) + list(range(11, 19)))] # Set 'nsslapd-accesslog-logbuffering' to 'on' if True, otherwise set it to 'off' standalone.config.logbuffering(True) ``` -------------------------------- ### Check Plugin Status with Python Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/plugin.md Shows how to check if a plugin is enabled using the `status` method. The assertion checks if the plugin's enabled state is `True`. ```python # True if nsslapd-pluginEnabled is 'on', False otherwise - change the name? assert(uniqplugin.status()) ``` -------------------------------- ### Accessing Directory Server Path Variables Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/paths.md Demonstrates how to retrieve specific path variables from the ds_paths module. ```default # You can get any variable from the list bellow. Like this: product = standalone.ds_paths.product variables = [ 'product', 'version', 'user', 'group', 'root_dn', 'prefix', 'bin_dir', 'sbin_dir', 'lib_dir', 'data_dir', 'tmp_dir', 'sysconf_dir', 'config_dir', 'schema_dir', 'cert_dir', 'local_state_dir', 'run_dir', 'lock_dir', 'log_dir', 'inst_dir', 'db_dir', 'backup_dir', 'ldif_dir', 'initconfig_dir', 'tmpfiles_d', ] ``` -------------------------------- ### Enable SSL/TLS for Directory Server Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Enable SSL/TLS encryption for the directory server instance with a single method call. ```python standalone.enable_tls() ``` -------------------------------- ### Importing all constants from lib389._constants Source: https://github.com/389ds/389-ds-base/blob/main/src/lib389/doc/source/guidelines.md Import all constants from `lib389._constants` using the wildcard `*` import if your code extensively uses many constants from this module. Be mindful of potential namespace conflicts. ```python from lib389._constants import * ``` -------------------------------- ### Clone your fork Source: https://github.com/389ds/389-ds-base/blob/main/docs/agents/contributing.md Clones the forked repository of 389-ds-base to your local machine. ```bash git clone https://github.com//389-ds-base.git cd 389-ds-base ```