#!/usr/bin/env bash
|
# The contents of this file are subject to the terms of the Common Development and
|
# Distribution License (the License). You may not use this file except in compliance with the
|
# License.
|
#
|
# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
|
# specific language governing permission and limitations under the License.
|
#
|
# When distributing Covered Software, include this CDDL Header Notice in each file and include
|
# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
|
# Header, with the fields enclosed by brackets [] replaced by your own identifying
|
# information: "Portions copyright [year] [name of copyright owner]".
|
#
|
# Portions copyright 2026 3A Systems, LLC.
|
|
# Default setup script
|
#
|
# What the instance is made of - the server itself, the backend, the entries the backend was
|
# asked to hold - is left to fail this script, which is what run.sh reads to decide whether
|
# the container may report itself healthy. The optional schema and data LDIFs below keep the
|
# tolerance they were written with.
|
|
echo "Setting up default OpenDJ instance"
|
|
# A replication server of the background join holds no data (#1178): it gets no backend for
|
# BASE_DN, and none of the entries below - entries there would replicate nowhere, and be
|
# served to any client that reaches it. run.sh marks a volume $INITIALIZE_PENDING before its
|
# bootstrap exactly when the background join runs; without the join the server holds its data
|
# as any other - one with neither would be healthy and serve nothing - and REPLICATION_ROLE
|
# is not read. The role is checked here as join.sh checks it, before anything is set up: a
|
# value the join refuses would otherwise leave a volume set up for another role than the one
|
# asked for. It is recorded on the volume, where join.sh reads it on every start: the volume
|
# is what makes the role, whatever REPLICATION_ROLE says later.
|
HOLDS_DATA=true
|
if [ -n "$INITIALIZE_PENDING" ] && [ -f "$INITIALIZE_PENDING" ]; then
|
role=${REPLICATION_ROLE:-combined}
|
case $role in
|
combined | directory) ;;
|
replication)
|
HOLDS_DATA=false
|
echo "REPLICATION_ROLE=replication: no backend is created for $BASE_DN, and no entries are loaded" ;;
|
*)
|
echo "REPLICATION_ROLE=$REPLICATION_ROLE is not one of combined, directory or replication" >&2
|
exit 1 ;;
|
esac
|
printf '%s\n' "$role" >"${REPLICATION_ROLE_FILE:-/opt/opendj/data/.replication-role}" || exit 1
|
fi
|
|
# The tools read only the first line of a password file, and a CR ends it as an LF does, so a
|
# password with a line break would be cut there - silently, as the root password set up would
|
# not be the one the container was given
|
cr=$(printf '\r')
|
nl='
|
'
|
case $ROOT_PASSWORD in
|
*"$cr"*|*"$nl"*)
|
echo "ROOT_PASSWORD must not contain a line break: the tools read only the first line of the password file" >&2
|
exit 1 ;;
|
esac
|
|
# The tools read the root password from a file, so that any password setup accepts reaches
|
# them as one value, and it does not show on the command line of a process while the tool
|
# runs. mktemp creates the file readable by its owner only. The EXIT trap does not run when the
|
# container is killed during the bootstrap, so the file goes to the tmpfs of /dev/shm where
|
# there is one, rather than to the writable layer of the container, and run.sh removes what a
|
# killed bootstrap left behind before anything else. On Kubernetes /dev/shm is shared by all
|
# the containers of the pod and outlives a restart of this one, which is what the removal in
|
# run.sh is for there; the name carries ADMIN_PORT, so that it removes only the file of this
|
# container. Busybox mktemp replaces only the last six X of the template.
|
PASSWORD_FILE=$(mktemp -p /dev/shm "opendj-setup-password.$ADMIN_PORT.XXXXXX" 2>/dev/null \
|
|| mktemp "/tmp/opendj-setup-password.$ADMIN_PORT.XXXXXX") || exit 1
|
# the trap also removes the base entry template below, which a failed import would leave in /tmp
|
BASE_TEMPLATE=
|
trap 'rm -f "$PASSWORD_FILE" ${BASE_TEMPLATE:+"$BASE_TEMPLATE"}' EXIT
|
printf '%s\n' "$ROOT_PASSWORD" >"$PASSWORD_FILE" || exit 1
|
|
# If any optional LDIF files are present load them
|
|
# There are multiple types of ldif files.
|
# This step makes plain copies.
|
# See below for imports via `ldapmodify`.
|
if [ -d /opt/opendj/bootstrap/config/schema/ ]; then
|
echo "Copying schema:"
|
mkdir -p /opt/opendj/template/config/schema
|
for file in /opt/opendj/bootstrap/config/schema/*; do
|
target_file="/opt/opendj/template/config/schema/$(basename -- "$file")"
|
echo "Copying $file to $target_file"
|
cp "$file" "$target_file"
|
done
|
fi
|
|
/opt/opendj/setup \
|
--cli \
|
-h localhost \
|
--ldapPort $PORT \
|
--ldapsPort $LDAPS_PORT \
|
--enableStartTLS $OPENDJ_SSL_OPTIONS \
|
--adminConnectorPort $ADMIN_PORT \
|
--rootUserDN "$ROOT_USER_DN" \
|
--rootUserPasswordFile "$PASSWORD_FILE" \
|
--acceptLicense \
|
--no-prompt \
|
--noPropertiesFile \
|
$SETUP_ARGS || exit 1
|
|
BACKEND_TYPE=${BACKEND_TYPE:-je}
|
BACKEND_DB_DIRECTORY=${BACKEND_DB_DIRECTORY:-db}
|
if [ "$HOLDS_DATA" = true ]; then
|
echo "creating backend: $BACKEND_TYPE db-directory: ${BACKEND_DB_DIRECTORY}"
|
|
/opt/opendj/bin/dsconfig create-backend -h localhost -p $ADMIN_PORT --bindDN "$ROOT_USER_DN" --bindPasswordFile "$PASSWORD_FILE" \
|
--backend-name=userRoot --type $BACKEND_TYPE --set "base-dn:$BASE_DN" --set "db-directory:$BACKEND_DB_DIRECTORY" \
|
--set enabled:true --no-prompt --trustAll || exit 1
|
fi
|
|
if [ "$HOLDS_DATA" = true ] && [ "$ADD_BASE_ENTRY" = "--addBaseEntry" ]; then
|
BASE_TEMPLATE=$(mktemp)
|
if [ ! -z ${SAMPLE_DATA} ]; then
|
echo "generating sample data..."
|
/opt/opendj/bin/makeldif -o $BASE_TEMPLATE -c suffix="$BASE_DN" -c numusers=$SAMPLE_DATA /opt/opendj/template/config/MakeLDIF/example.template || exit 1
|
/opt/opendj/bin/import-ldif --ldifFile $BASE_TEMPLATE \
|
--backendID=userRoot --bindDN "$ROOT_USER_DN" --bindPasswordFile "$PASSWORD_FILE" || exit 1
|
else
|
echo "creating base entry..."
|
echo "branch: $BASE_DN" > $BASE_TEMPLATE
|
/opt/opendj/bin/import-ldif --templateFile $BASE_TEMPLATE \
|
--backendID=userRoot --bindDN "$ROOT_USER_DN" --bindPasswordFile "$PASSWORD_FILE" || exit 1
|
fi
|
rm $BASE_TEMPLATE
|
fi
|
|
|
# There are multiple types of ldif files.
|
# The steps below import ldifs via `ldapmodify`.
|
# See above for plain copying of ldif files.
|
|
if [ -d /opt/opendj/bootstrap/schema/ ]; then
|
echo "Loading initial schema:"
|
for file in /opt/opendj/bootstrap/schema/*; do
|
echo "Loading $file ..."
|
/opt/opendj/bin/ldapmodify -D "$ROOT_USER_DN" -h localhost -p $PORT -j "$PASSWORD_FILE" -f "$file"
|
done
|
fi
|
|
if [ "$HOLDS_DATA" = true ] && [ -d /opt/opendj/bootstrap/data/ ]; then
|
# allow pre encoded passwords; the port is named, as the tool would otherwise go to 4444
|
# whatever ADMIN_PORT the server listens on, and the entries carrying them would be refused
|
/opt/opendj/bin/dsconfig \
|
set-password-policy-prop \
|
-h localhost \
|
-p $ADMIN_PORT \
|
--bindDN "$ROOT_USER_DN" \
|
--bindPasswordFile "$PASSWORD_FILE" \
|
--policy-name "Default Password Policy" \
|
--set allow-pre-encoded-passwords:true \
|
--trustAll \
|
--no-prompt
|
|
for file in /opt/opendj/bootstrap/data/*; do
|
echo "Loading $file ..."
|
/opt/opendj/bin/ldapmodify -D "$ROOT_USER_DN" -h localhost -p $PORT -j "$PASSWORD_FILE" -f "$file" --continueOnError
|
done
|
fi
|