feat: add multi-master replication support
Some checks failed
CI Pipeline / lint (push) Successful in 20s
CI Pipeline / build (push) Successful in 56s
CI Pipeline / test (push) Failing after 1m32s
CI Pipeline / security-scan (push) Successful in 1m21s
CI Pipeline / autotag (push) Has been skipped
CI Pipeline / push (push) Has been skipped
CI Pipeline / update-cd (push) Has been skipped
Some checks failed
CI Pipeline / lint (push) Successful in 20s
CI Pipeline / build (push) Successful in 56s
CI Pipeline / test (push) Failing after 1m32s
CI Pipeline / security-scan (push) Successful in 1m21s
CI Pipeline / autotag (push) Has been skipped
CI Pipeline / push (push) Has been skipped
CI Pipeline / update-cd (push) Has been skipped
- Add syncprov module to init-config.sh - Create init-replication.sh for configuring N-way multi-master - Update entrypoint to handle replication configuration - Support LDAP_REPLICATION_ENABLED, LDAP_SERVER_ID, LDAP_REPLICATION_HOSTS - Replica servers can sync DIT from existing masters
This commit is contained in:
parent
989ad3fbfb
commit
1b24516663
@ -44,6 +44,12 @@ export LDAP_TLS_VERIFY_CLIENT="${LDAP_TLS_VERIFY_CLIENT:-try}"
|
||||
export LDAP_LOG_LEVEL="${LDAP_LOG_LEVEL:-256}"
|
||||
export LDAP_READONLY="${LDAP_READONLY:-false}"
|
||||
|
||||
# Replication settings
|
||||
export LDAP_REPLICATION_ENABLED="${LDAP_REPLICATION_ENABLED:-false}"
|
||||
export LDAP_SERVER_ID="${LDAP_SERVER_ID:-1}"
|
||||
export LDAP_REPLICATION_HOSTS="${LDAP_REPLICATION_HOSTS:-}"
|
||||
export LDAP_BOOTSTRAP_PRIMARY="${LDAP_BOOTSTRAP_PRIMARY:-false}"
|
||||
|
||||
log_info "OpenLDAP Container Starting"
|
||||
log_info "Domain: $LDAP_DOMAIN"
|
||||
log_info "Base DN: $LDAP_BASE_DN"
|
||||
@ -53,36 +59,43 @@ log_info "Organisation: $LDAP_ORGANISATION"
|
||||
if [ ! -f /var/lib/openldap/openldap-data/data.mdb ]; then
|
||||
log_info "First run - initializing OpenLDAP..."
|
||||
|
||||
# Initialize cn=config
|
||||
# Initialize cn=config (always needed)
|
||||
/scripts/init-config.sh
|
||||
|
||||
# Load schemas in order
|
||||
# Load schemas in order (always needed)
|
||||
/scripts/init-schemas.sh
|
||||
|
||||
# Configure overlays
|
||||
# Configure overlays (always needed)
|
||||
/scripts/init-overlays.sh
|
||||
|
||||
# Create base DIT
|
||||
/scripts/init-dit.sh
|
||||
# Determine if we should initialize DIT or replicate from peer
|
||||
# If replication is enabled and we're not the bootstrap primary, skip DIT init
|
||||
if [ "$LDAP_REPLICATION_ENABLED" = "true" ] && [ "$LDAP_BOOTSTRAP_PRIMARY" != "true" ]; then
|
||||
log_info "Replication enabled - this server will sync DIT from peers"
|
||||
log_info "Skipping local DIT initialization..."
|
||||
else
|
||||
# Create base DIT
|
||||
/scripts/init-dit.sh
|
||||
|
||||
# Configure ACLs
|
||||
/scripts/init-acls.sh
|
||||
# Configure ACLs
|
||||
/scripts/init-acls.sh
|
||||
|
||||
# Create service accounts if requested
|
||||
if [ "$LDAP_CREATE_SERVICE_ACCOUNTS" = "true" ]; then
|
||||
/scripts/init-services.sh
|
||||
fi
|
||||
# Create service accounts if requested
|
||||
if [ "$LDAP_CREATE_SERVICE_ACCOUNTS" = "true" ]; then
|
||||
/scripts/init-services.sh
|
||||
fi
|
||||
|
||||
# Process custom LDIF files if present
|
||||
if [ -d /ldif/custom ] && [ "$(ls -A /ldif/custom 2>/dev/null)" ]; then
|
||||
log_info "Processing custom LDIF files..."
|
||||
for ldif in /ldif/custom/*.ldif; do
|
||||
if [ -f "$ldif" ]; then
|
||||
log_info "Loading: $ldif"
|
||||
ldapadd -x -H "$LDAPI_SOCKET" -D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" -f "$ldif" || \
|
||||
log_warn "Failed to load $ldif (may already exist)"
|
||||
fi
|
||||
done
|
||||
# Process custom LDIF files if present
|
||||
if [ -d /ldif/custom ] && [ "$(ls -A /ldif/custom 2>/dev/null)" ]; then
|
||||
log_info "Processing custom LDIF files..."
|
||||
for ldif in /ldif/custom/*.ldif; do
|
||||
if [ -f "$ldif" ]; then
|
||||
log_info "Loading: $ldif"
|
||||
ldapadd -x -H "$LDAPI_SOCKET" -D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" -f "$ldif" || \
|
||||
log_warn "Failed to load $ldif (may already exist)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Initialization complete."
|
||||
@ -108,7 +121,38 @@ fi
|
||||
|
||||
log_info "Starting slapd with URLs: $SLAPD_URLS"
|
||||
|
||||
# Start slapd
|
||||
# If replication is enabled, start slapd in background first to configure replication
|
||||
if [ "$LDAP_REPLICATION_ENABLED" = "true" ]; then
|
||||
log_info "Starting slapd in background for replication configuration..."
|
||||
|
||||
/usr/sbin/slapd -h "$SLAPD_URLS" \
|
||||
-F /etc/openldap/slapd.d \
|
||||
-u ldap -g ldap &
|
||||
|
||||
SLAPD_PID=$!
|
||||
|
||||
# Wait for slapd to be ready
|
||||
log_info "Waiting for slapd to be ready..."
|
||||
sleep 2
|
||||
for i in $(seq 1 30); do
|
||||
if ldapsearch -x -H ldap://localhost -b "" -s base "objectClass=*" >/dev/null 2>&1; then
|
||||
log_info "slapd is ready"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Configure replication
|
||||
/scripts/init-replication.sh
|
||||
|
||||
# Stop background slapd gracefully
|
||||
log_info "Restarting slapd in foreground mode..."
|
||||
kill $SLAPD_PID 2>/dev/null || true
|
||||
wait $SLAPD_PID 2>/dev/null || true
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Start slapd in foreground (final)
|
||||
exec /usr/sbin/slapd -h "$SLAPD_URLS" \
|
||||
-F /etc/openldap/slapd.d \
|
||||
-u ldap -g ldap \
|
||||
|
||||
@ -31,6 +31,7 @@ olcModuleLoad: memberof.so
|
||||
olcModuleLoad: refint.so
|
||||
olcModuleLoad: unique.so
|
||||
olcModuleLoad: ppolicy.so
|
||||
olcModuleLoad: syncprov.so
|
||||
|
||||
dn: cn=schema,cn=config
|
||||
objectClass: olcSchemaConfig
|
||||
|
||||
129
scripts/init-replication.sh
Executable file
129
scripts/init-replication.sh
Executable file
@ -0,0 +1,129 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
. /scripts/utils.sh
|
||||
|
||||
# Skip if replication not enabled
|
||||
if [ "$LDAP_REPLICATION_ENABLED" != "true" ]; then
|
||||
log_info "Replication not enabled, skipping..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate required variables
|
||||
if [ -z "$LDAP_SERVER_ID" ]; then
|
||||
log_error "LDAP_SERVER_ID is required for replication"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$LDAP_REPLICATION_HOSTS" ]; then
|
||||
log_error "LDAP_REPLICATION_HOSTS is required for replication"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use admin credentials for replication if not specified
|
||||
LDAP_REPLICATION_DN="${LDAP_REPLICATION_DN:-cn=admin,$LDAP_BASE_DN}"
|
||||
LDAP_REPLICATION_PASSWORD="${LDAP_REPLICATION_PASSWORD:-$LDAP_ADMIN_PASSWORD}"
|
||||
|
||||
log_info "Configuring multi-master replication..."
|
||||
log_info "Server ID: $LDAP_SERVER_ID"
|
||||
log_info "Replication hosts: $LDAP_REPLICATION_HOSTS"
|
||||
|
||||
# Wait for slapd to be ready
|
||||
wait_for_slapd 30 "$LDAPI_SOCKET"
|
||||
|
||||
# Configure serverID in cn=config
|
||||
log_info "Setting serverID..."
|
||||
cat > /tmp/repl-serverid.ldif << EOF
|
||||
dn: cn=config
|
||||
changetype: modify
|
||||
replace: olcServerID
|
||||
olcServerID: ${LDAP_SERVER_ID}
|
||||
EOF
|
||||
|
||||
ldapmodify -Y EXTERNAL -H "$LDAPI_SOCKET" -f /tmp/repl-serverid.ldif 2>/dev/null || \
|
||||
log_warn "ServerID may already be set"
|
||||
|
||||
# Configure syncprov overlay on the database
|
||||
log_info "Configuring syncprov overlay..."
|
||||
cat > /tmp/repl-syncprov.ldif << EOF
|
||||
dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config
|
||||
changetype: add
|
||||
objectClass: olcOverlayConfig
|
||||
objectClass: olcSyncProvConfig
|
||||
olcOverlay: syncprov
|
||||
olcSpCheckpoint: 100 10
|
||||
olcSpSessionlog: 100
|
||||
EOF
|
||||
|
||||
ldapmodify -Y EXTERNAL -H "$LDAPI_SOCKET" -f /tmp/repl-syncprov.ldif 2>/dev/null || \
|
||||
log_warn "syncprov overlay may already exist"
|
||||
|
||||
# Build syncrepl configuration for each peer
|
||||
# Format: LDAP_REPLICATION_HOSTS="ldap://server1.example.com,ldap://server2.example.com"
|
||||
REPLICA_NUM=0
|
||||
SYNCREPL_CONFIG=""
|
||||
|
||||
# Parse the comma-separated list of hosts
|
||||
OLD_IFS="$IFS"
|
||||
IFS=','
|
||||
for host in $LDAP_REPLICATION_HOSTS; do
|
||||
REPLICA_NUM=$((REPLICA_NUM + 1))
|
||||
|
||||
# Trim whitespace
|
||||
host=$(echo "$host" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
|
||||
log_info "Adding replication peer $REPLICA_NUM: $host"
|
||||
|
||||
SYNCREPL_CONFIG="${SYNCREPL_CONFIG}
|
||||
olcSyncRepl: rid=$(printf '%03d' $REPLICA_NUM)
|
||||
provider=${host}
|
||||
bindmethod=simple
|
||||
binddn=\"${LDAP_REPLICATION_DN}\"
|
||||
credentials=${LDAP_REPLICATION_PASSWORD}
|
||||
searchbase=\"${LDAP_BASE_DN}\"
|
||||
scope=sub
|
||||
schemachecking=on
|
||||
type=refreshAndPersist
|
||||
retry=\"60 +\"
|
||||
timeout=1"
|
||||
done
|
||||
IFS="$OLD_IFS"
|
||||
|
||||
# Configure syncrepl and mirrormode on the database
|
||||
log_info "Configuring syncrepl and mirrormode..."
|
||||
cat > /tmp/repl-syncrepl.ldif << EOF
|
||||
dn: olcDatabase={1}mdb,cn=config
|
||||
changetype: modify
|
||||
replace: olcSyncRepl
|
||||
${SYNCREPL_CONFIG}
|
||||
-
|
||||
replace: olcMirrorMode
|
||||
olcMirrorMode: TRUE
|
||||
EOF
|
||||
|
||||
ldapmodify -Y EXTERNAL -H "$LDAPI_SOCKET" -f /tmp/repl-syncrepl.ldif || {
|
||||
log_error "Failed to configure syncrepl"
|
||||
cat /tmp/repl-syncrepl.ldif
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Add additional indexes for replication
|
||||
log_info "Adding replication indexes..."
|
||||
cat > /tmp/repl-indexes.ldif << EOF
|
||||
dn: olcDatabase={1}mdb,cn=config
|
||||
changetype: modify
|
||||
add: olcDbIndex
|
||||
olcDbIndex: entryCSN eq
|
||||
-
|
||||
add: olcDbIndex
|
||||
olcDbIndex: entryUUID eq
|
||||
EOF
|
||||
|
||||
ldapmodify -Y EXTERNAL -H "$LDAPI_SOCKET" -f /tmp/repl-indexes.ldif 2>/dev/null || \
|
||||
log_warn "Indexes may already exist"
|
||||
|
||||
# Cleanup
|
||||
rm -f /tmp/repl-*.ldif
|
||||
|
||||
log_info "Multi-master replication configured successfully"
|
||||
log_info "This server (ID=$LDAP_SERVER_ID) will replicate with $REPLICA_NUM peer(s)"
|
||||
Loading…
x
Reference in New Issue
Block a user