Conversation
…alth check may probe it, and import online in the Docker test The server is PID 1 of the container from the first start on, so stop-ds in "Docker test" stopped the container and the offline import that followed had nothing to run in. The step now imports online and checks that docker stop stops the server cleanly, as OpenIdentityPlatform#1098 does. The server setup started is stopped before the bootstrap marker is written, so that the health check never reports it healthy just before it goes down.
…alth check may probe it, and import online in the Docker test The server is PID 1 of the container from the first start on, so stop-ds in "Docker test" stopped the container and the offline import that followed had nothing to run in. The step now imports online and checks that docker stop stops the server cleanly, as OpenIdentityPlatform#1098 does. The server setup started is stopped before the bootstrap marker is written, so that the health check never reports it healthy just before it goes down.
maximthomas
left a comment
There was a problem hiding this comment.
praise: The server is now PID 1 on the first start as well, and the stop sits where the health check cannot see it.
opendj-packages/opendj-docker/run.sh:88stops the bootstrap's server and:107execsstart-ds --nodetach, so a first start and a restart end in the same process tree.- The stop runs before
touch "$BOOTSTRAP_COMPLETE"(run.sh:103), so theHEALTHCHECK(Dockerfile:78) never reports the bootstrap's server healthy just before it goes down. - The Docker test step now requires
docker stop -t 60to finish in under 50 s with an exit code other than 137 (.github/workflows/build.yml:535-540), which is exactly the #1085 symptom.
issue (blocking): On a first start the server now comes up, goes down and comes up again, and the in-repo benchmark seeds its users into that gap.
opendj-packages/opendj-docker/run.sh:67-107, .github/benchmark/compare-opendj.sh:53-74, .github/workflows/benchmark.yml:180-193
setup.sh starts the server and creates the base entry, so wait_dj returns as soon as the bootstrap's server answers. run.sh:88 then stops that server, and the ldapadd -f people.ldif ... || true runs during the stop/start window: it fails without an error, and JMeter then binds as users that do not exist. This PR's build-docker job (run 36010414848) logs 69729 / 74409 / 56464 BIND | 49 | Invalid Credentials on the JE, PDB and Build images. On the base commit, master (run 36001081168) logs 0 / 3 / 0. The job stays green, so the benchmark numbers mean nothing from now on. benchmark.yml has the same wait and ldapadd || true, followed by a dsconfig (:193) with no || true. The one readiness signal that stays correct across the restart is the container's health status.
wait_dj() { # healthy once the image has a HEALTHCHECK; the first start restarts the server
for _ in $(seq 1 90); do
case "$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' opendj-bench 2>/dev/null)" in
healthy) return 0 ;;
"") ldapsearch -x -H ldap://localhost:1389 -D "cn=Directory Manager" -w password \
-b "$BASEDN" -s base dn >/dev/null 2>&1 && return 0 ;;
esac
sleep 2
done
return 1
}Or: the same loop in benchmark.yml:180-186, with the container opendj.
suggestion (non-blocking): No test checks that stop-ds runs before the .bootstrap-complete marker is written.
opendj-packages/opendj-docker/run.sh:88, :103, .github/workflows/build.yml:526-528
Suppose stop-ds is moved after the touch. The Docker test step then fails only when a 30 s health probe lands in the 1-3 s between the marker and the stop. Otherwise it sees the same sequence as the head, so that mutant passes in most runs (traced, not run). The stop/restart checks at :535-544 do not see the order, because the baseline count is read after the bootstrap's stop in both orders.
# right after `docker run` in both Docker test steps: the bootstrap's server is down before the marker exists
timeout 3m bash -c 'until docker exec test sh -c "test -f \"\$BOOTSTRAP_COMPLETE\"" 2>/dev/null; do sleep 0.2; done'
test "$(docker exec test grep -c "The Directory Server is now stopped" /opt/opendj/data/logs/errors)" -ge 1Pin: the head always passes, because the stop record exists whenever the marker does. The mutant fails unless the 0.2 s poll misses the stop window. This assumes setup itself never stops the server: setup.sh has no stop-ds and no --doNotStart. Not run.
suggestion (non-blocking): The exit status of the new ./bin/stop-ds is ignored.
opendj-packages/opendj-docker/run.sh:88
stop-ds exits non-zero when the server is running but logs/server.pid is missing (stop-ds:183-185), or when WaitForFileDelete gives up on a slow shutdown (stop-ds:168-173). In that case the marker is still written, start-ds cannot take the server lock, and the container stops without a line saying why. Before this change the bootstrap's server stayed up. The failure path was read, not run, and it is rare.
./bin/stop-ds || { BOOTSTRAPPED=false; echo "Could not stop the server started by the bootstrap, this container will not report itself healthy"; }f6cb09d to
1803490
Compare
|
Thanks. Round 2 is 1803490, rebased onto the current issue (blocking), the benchmark seeds into the restart gap: agreed. The job logs you quoted show it: 69729 / 74409 / 56464
Run locally with the new suggestion, no test pins the stop before the marker: taken, in both Run locally with the two lines as they are in suggestion, the exit status of |
…alth check may probe it, and import online in the Docker test The server is PID 1 of the container from the first start on, so stop-ds in "Docker test" stopped the container and the offline import that followed had nothing to run in. The step now imports online and checks that docker stop stops the server cleanly, as OpenIdentityPlatform#1098 does. The server setup started is stopped before the bootstrap marker is written, so that the health check never reports it healthy just before it goes down.
maximthomas
left a comment
There was a problem hiding this comment.
praise: The round-1 blocker is fixed with the one signal that survives the restart, and the stop-before-marker order is now pinned.
.github/benchmark/compare-opendj.sh:58-69and.github/workflows/benchmark.yml:185-193wait forhealthybefore seeding.run.sh:107writes the marker only after the stop atrun.sh:90, so no seed can land between the two servers..github/workflows/build.yml:529-530and:710-711wait for the marker and require the "The Directory Server is now stopped" record to be in the log already, in both docker jobs.
issue (blocking): A replica started together with its master runs its only dsreplication enable while the master is restarting, and never tries again.
opendj-packages/opendj-docker/run.sh:89-111, opendj-packages/opendj-docker/bootstrap/replicate.sh:26-51, :85-116
On a first start the master now stops the bootstrap's server (run.sh:90) and execs start-ds (run.sh:111), so port 4444 is down for the stop plus the start: about 3 s plus 10-16 s in CI's container logs. A replica that bootstrapped at the same time runs replicate.sh, which does sleep 5 and then one dsreplication enable --host1 $MASTER_SERVER. That call connects once and returns ERROR_CONNECTING on failure (ReplicationCliMain.java:3605-3611), and it lands in the window whenever both containers start together: Compose without condition: service_healthy, or the openshift template's StatefulSet scaled past 1 (OrderedReady, no readinessProbe). run.sh:75 then withholds the marker, so the replica never reports healthy and has no replication. Because ./data/config now exists, every restart takes run.sh:36-54, which never runs replicate.sh again; only wiping the volume recovers it. Before this PR the bootstrap's server stayed up, and the same start succeeded. The path is traced through the code; how often the lockstep start happens has not been measured.
# replicate.sh — the master stops and restarts its server once at the end of its own
# first start (run.sh), so a call that lands in that gap cannot connect: try again for
# up to 5 minutes.
retry() {
for _ in $(seq 1 30); do
"$@" && return 0
echo "$1 failed, trying again in 10 s"
sleep 10
done
return 1
}
# in each OPENDJ_REPLICATION_TYPE branch:
retry /opt/opendj/bin/dsreplication enable ... || exit 1
retry /opt/opendj/bin/dsreplication initialize ... || exit 1Or: a README line saying a replica must be started only after its master is healthy. That is weaker, because it leaves the openshift template exposed.
suggestion (non-blocking): Nothing fails when the benchmark seed misses, so no check covers the new wait.
.github/benchmark/compare-opendj.sh:81-83, .github/workflows/benchmark.yml:185-195
After the wait, compare-opendj.sh continues past WARN: ... not ready in time and past ldapadd ... || true. benchmark.yml leaves its loop with no message when the server never gets ready, and its ldapadd is also || true; both behave as on master. If the port-only wait comes back, every job stays green, and the round-1 numbers (69729 / 74409 / 56464 BIND | 49) appear only in the step summary.
# compare-opendj.sh, after the ldapadd at :82-83
# (A_VER="$(bench_one ...)" under set -euo pipefail stops the script)
ldapsearch -x -H ldap://localhost:1389 -D "cn=Directory Manager" -w password \
-b "ou=People,$BASEDN" -s base dn >/dev/null 2>&1 \
|| { echo "ERROR: $image: ou=People was not seeded" >&2; return 1; }
# benchmark.yml, after the ldapadd at :194-195
ldapsearch -x -H ldap://localhost:1389 -D "cn=Directory Manager" -w password \
-b "ou=People,$BASEDN" -s base dn >/dev/nullPin: this passes at this head, since ou=People is there once the container is healthy. With the health test removed from the wait, it fails in every run whose seed lands in the restart window.
nitpick (non-blocking): The new wait comments say an add made during the restart "is lost". In fact the add fails.
.github/benchmark/compare-opendj.sh:53-57, .github/workflows/benchmark.yml:180-184
An add that the bootstrap's server completed survives the stop. stop-ds returns only once server.pid is gone at JVM exit, after the backends are closed, and nothing replaces the backend before start-ds. A request sent during the window gets connection refused or closed, and || true hides that. This is what the README hunk says: "can have its first requests fail".
# first: on a first start the server the bootstrap started answers, then is stopped and
# started again, and a request sent in between fails. An older image's health check…ontainer that bootstrapped its instance On the first start run.sh kept bash as PID 1 behind `tail -f /dev/null`, so SIGTERM was never delivered and the container was killed at the end of the stop timeout without stopping the server. The server that setup started is now stopped once the bootstrap is through, before the health marker is written, and started again with exec, so it is PID 1 as on every restart. The Docker test stopped and started the server inside the container, which only worked because of this; it now imports online, checks that `docker stop` stops the server cleanly, and checks the restarted container. Fixes OpenIdentityPlatform#1085
…re seeding the benchmark, and check that the bootstrap's server is down before the marker On a first start the server the bootstrap started is stopped and started again, so waiting for it to answer is no longer enough: the benchmark seeded ou=People into that gap and ran against a directory without its users. Both benchmark waits now require a healthy container where the image has a health check, still search the base entry, which older images need, and last as long as the health check's start period. The Docker test steps check that the bootstrap's server has logged its stop by the time the marker is written. run.sh says so when stop-ds fails, and still tries the start.
…ng at the end of its first start, and fail the benchmark when its seed missed A replica started together with its master reached it while the master stopped the server its bootstrap started and started it again, and its one dsreplication enable failed with ERROR_CONNECTING. replicate.sh now runs enable again when it exits 8, the only code it returns before changing anything, and initialize, initialize-all and the dsconfig on the master again after any failure, every 10 s for up to 5 minutes. A failed enable ends the script instead of running initialize. Both Docker test steps take the master off the network while the replica sleeps before its first try, and bring it back once the replica says it tries again. The benchmark checks that ou=People was seeded, and stops when it was not.
1803490 to
df6b632
Compare
|
Thanks. Round 3 is df6b632, rebased onto the current issue (blocking), a replica started together with its master: agreed for
The openshift template is not affected: it passes Pinned in both Run locally with the branch's
One gap remains, and it is older than this PR: suggestion, nothing fails when the seed misses: taken, with one change to the snippet. In nitpick, "is lost": taken, in both comments: "a request sent in between fails". |
…alth check may probe it, and import online in the Docker test The server is PID 1 of the container from the first start on, so stop-ds in "Docker test" stopped the container and the offline import that followed had nothing to run in. The step now imports online and checks that docker stop stops the server cleanly, as OpenIdentityPlatform#1098 does. The server setup started is stopped before the bootstrap marker is written, so that the health check never reports it healthy just before it goes down.
maximthomas
left a comment
There was a problem hiding this comment.
praise: The round-3 commit fixes the round-2 blocker where it happens and pins the fix with a real disconnect.
retryinreplicate.sh:57-70retriesdsreplication enableonly on exit 8 and the repeatable tools on any failure.|| exitat:89,:117and:148stops a failed enable from going on toinitialize.build.yml:604-608takes the master off the network around the replica's first try and requires "exited with 8, trying again". At the base that wait times out.- Both benchmark seeds now fail on a missing
ou=People:compare-opendj.shthroughreturn 1underset -e, andbenchmark.ymlthrough|| { ...; false; }.
issue (non-blocking): With srs, a DS replica that restarts right after its own replicate.sh can miss a later replica's initialize-all. It then stays in BAD_GEN_ID while it reports healthy.
opendj-packages/opendj-docker/bootstrap/replicate.sh:121, opendj-packages/opendj-docker/run.sh:94
Each srs DS pushes its own data with initialize-all --hostname $MYHOSTNAME. The push goes to the DSs connected at that moment (ReplicationDomain.java:1716) and fails only when there are none (:1623-1628). Take one RS and three DS started together. DS1 pushes, then stops at run.sh:94 for the new stop/start. DS3's push lands in that window and succeeds against DS2 alone, so retry any never fires. The RS then takes DS3's generation ID. DS1 comes back with its own data and generation ID and goes to BAD_GEN_ID (DataServerHandler.java:134-138). Its replicate.sh does not run again and the marker is already written. The IDs differ whenever the entries were added over LDAP (setup.sh:92-105, ldapmodify of bootstrap/data, random entryUUID). At the base, tail -f kept DS1's server up and it received the push. Not run: this needs one RS and three DS containers, and CI has no srs job.
With `OPENDJ_REPLICATION_TYPE=srs`, start the directory server replicas one at a time, each once the
previous one is healthy: every replica pushes its data to the replicas connected at that moment,
and one that is restarting at the end of its own first start misses it.Or: before writing the marker, check that the domain is not in BAD_GEN_ID.
issue (non-blocking): dsreplication enable can exit 8 after it has written configuration. The comment at replicate.sh:52-54 and the PR description say it cannot.
opendj-packages/opendj-docker/bootstrap/replicate.sh:52-54, opendj-server-legacy/src/main/java/org/opends/server/tools/dsreplication/ReplicationCliMain.java:6486-6509
Exit 8 does come before any write for the two admin connections (:3605-3611). updateConfiguration then writes the ADS, configureServer and the first domain, and reconnects to every server in the topology cache (:6494). An LdapException there is thrown as ERROR_CONNECTING (:6505-6509). Suppose a third server is up when the cache loads and gone by the loop, for example an earlier replica inside its own run.sh:94 stop/start. Then enable exits 8 after those writes, and retry 8 runs a partly applied enable again. Whether that second enable completes or exits 5 is not traced.
# dsreplication enable exits 8 (ERROR_CONNECTING) when it cannot connect or bind to one of the two
# servers, which it checks before it changes anything, and also when another server of the topology
# cannot be reached after it has written to the first two. Only that exit code is tried again: an
# enable that failed otherwise may have replicated the base DN already, and a second one then fails.suggestion (non-blocking): Nothing pins that only exit 8 is retried, or that a failed enable ends replicate.sh.
opendj-packages/opendj-docker/bootstrap/replicate.sh:80, :89, .github/workflows/build.yml:604-608, :840-844
The only CI road makes enable fail with 8 and then succeed. Change retry 8 to retry any at :80 and the job still prints the same line and stays green. Remove || exit at :89 and the job never reaches it. The pin below runs a second enable of the already replicated base DN once test_replica is healthy. With retry any, the output gets "trying again". Without || exit, it gets "initializing replication". The pin relies on a second enable exiting non-zero (5 per ReplicationCliMain.java:3629-3634). Under the step's set -e a failing ! grep would not stop the step, hence the ifs.
out=$(docker exec -e BASE_DN=dc=example,dc=com -e ROOT_USER_DN="cn=Directory Manager" test_replica \
timeout 90 /opt/opendj/bootstrap/replicate.sh 2>&1) && { echo "a second enable succeeded"; exit 1; }
if grep -q "trying again" <<<"$out"; then echo "a non-8 enable failure was retried"; exit 1; fi
if grep -q "initializing replication" <<<"$out"; then echo "initialize ran after a failed enable"; exit 1; fisuggestion (non-blocking): The sdsr enable retry and the retry any on initialize have no case that can fail.
.github/workflows/build.yml:609-610, opendj-packages/opendj-docker/bootstrap/replicate.sh:94, :133, :152
test_replica_sdsr starts only once the master and test_replica are healthy, so its enable and its initialize succeed on the first try. Dropping retry 8 at :133, or retry any at :94/:152, leaves both docker jobs green. The same disconnect as for test_replica pins the sdsr enable. An initialize case would need the disconnect to land between "initializing replication" and the tool's connect, which is racy.
timeout 5m bash -c 'until docker logs test_replica_sdsr 2>&1 | grep -q "Will sleep for a bit"; do sleep 0.2; done'
docker network disconnect test_replication test_master
timeout 2m bash -c 'until docker logs test_replica_sdsr 2>&1 | grep -q "dsreplication enable exited with 8, trying again"; do sleep 1; done'
docker network connect --alias dj-master test_replication test_mastersuggestion (non-blocking): A failed bind also exits 8, so a replica with the wrong ROOT_PASSWORD is retried for 5 minutes.
opendj-packages/opendj-docker/bootstrap/replicate.sh:63, opendj-server-legacy/src/main/java/org/opends/server/tools/dsreplication/ReplicationCliMain.java:3752-3768
createAdministrativeConnection collects every LdapException from new ConnectionWrapper(...), invalid credentials included, and enableReplication returns ERROR_CONNECTING for all of them (:3605-3611). A misconfigured replica ends up unhealthy, which is right. It just gets there after about 5 minutes of "dsreplication enable exited with 8, trying again in 10 s". Saying so next to the retry is enough:
# A wrong root DN or password also exits 8, so it fails only once the 5 minutes are over.question (non-blocking): Is an enable that is still running when the master stops meant to be covered by the README's "so that window does not fail its replication setup"?
opendj-packages/opendj-docker/README.md:35-37
Suppose the master's stop-ds lands while the replica's enable is connected and writing. The write fails as ERROR_UPDATING_ADS (14), or as 11 or 17 in the other phases. That code is not retried, || exit ends replicate.sh, and the replica never becomes healthy. The comment at replicate.sh:52-54 states this choice, so as README wording this is minor. If the sentence is meant as a guarantee, it is an uncovered road of the round-2 blocker. Not run: it needs a master stopped mid-enable.
A replica set up with `MASTER_SERVER` tries a master it cannot connect to again, every 10 s for up
to 5 minutes, so a master that is down when the replica reaches it does not fail its replication
setup; one that stops while `dsreplication enable` is writing to it still does.nitpick (non-blocking): After the 30th failure, retry still logs "trying again in 10 s" and sleeps before it returns.
opendj-packages/opendj-docker/bootstrap/replicate.sh:60-69
retry() {
local on=$1 rc i
shift
for i in $(seq 1 30); do
"$@" && return 0
rc=$?
if [ "$on" != any ] && [ "$rc" -ne "$on" ] || [ "$i" -eq 30 ]; then
return $rc
fi
echo "$(basename "$1") $2 exited with $rc, trying again in 10 s"
sleep 10
done
}… replica tries again, and document what the retry does not cover replicate.sh - The comment on retry no longer says that exit 8 means nothing was written: dsreplication enable also exits 8 when another server of the topology cannot be reached after it has written to the first two. It also says that a wrong root DN or password exits 8, so it fails only once the 5 minutes are over. - retry returns after its 30th failure instead of saying it will try again and sleeping another 10 s. README.md - A master that stops while dsreplication enable is writing to it still fails the replica's setup; the retry covers only a master that cannot be reached. - With OPENDJ_REPLICATION_TYPE=srs the directory server replicas are to be started one at a time: each pushes its data to the replicas connected at that moment, and one restarting at the end of its own first start misses it and stays in a bad generation ID. build.yml (Docker test replication, both docker jobs) - The sdsr replica's enable is pinned the same way as the simple one's: the master is taken off the network until the replica logs that it tries again. - replicate.sh is run once more on the healthy simple replica. Its enable of a base DN already replicated has to end it with exit 5, with no "trying again" and no "initializing replication".
|
Round 4 is 76bdaf0, on the same issue, issue, exit 8 after writes: agreed. suggestion, pin "only 8" and suggestion, pin the I left the suggestion, wrong password exits 8: taken, the comment line next to question, the README sentence: no, it is not meant as a guarantee. It now uses your wording: a master that is down when the replica reaches it does not fail the setup; one that stops while nitpick, the 30th failure: taken, with your |
Fixes #1085
Problem
On the first start of a container (empty data volume)
run.shdid notexecthe server: setup had started it in the background, and the script ended intail -f /dev/nullwithbashas PID 1. A PID 1 without aSIGTERMhandler never receives the signal, sodocker stop/ pod termination waited out the whole timeout and thenSIGKILLed everything; the server was never stopped cleanly.Change
opendj-packages/opendj-docker/run.sh./bin/stop-ds; the existingexec ./bin/start-ds --nodetachthen starts it as PID 1, exactly as on a restart.stop-dsexits 0 when the server is not running, so a customBOOTSTRAPthat leaves it stopped still works.SECRET_VOLUMEand before the.bootstrap-completemarker (Report the OpenDJ container healthy only once its bootstrap has succeeded #898) is written. Stopping after the marker let the health check report the bootstrap's server healthy just before it went down - the nextdsconfigthen failed with "Server Connection Closed" (seen while testing this change).status | grep Started+tail -f /dev/nullblock is gone.stop-dsfails,run.shsays so and still tries the start: a server that is still stopping makesstart-dsfail on the server lock, and one that stopped late lets it run.A first start now has a short window between the bootstrap's server going down and the final one coming up. The health check is not affected: the marker is written after the stop, so only the server that keeps running can report healthy.
opendj-packages/opendj-docker/bootstrap/replicate.shdsreplication enablethen failed withERROR_CONNECTING, leaving it unhealthy and unreplicated for good. The tools are now tried again every 10 s for up to 5 minutes:enableonly when it exits 8 (ERROR_CONNECTING: mostly it could not connect or bind to one of the two servers, which it checks before it changes anything, but it also exits 8 when another server of the topology cannot be reached after it has written to the first two; any other failure is final, as a secondenableof a base DN already replicated exits 5; a wrong root DN or password also exits 8 and so fails only after the 5 minutes), andinitialize,initialize-alland thedsconfigon the master after any failure. A failedenableends the script instead of going on toinitialize..github/benchmark/compare-opendj.sh,.github/workflows/benchmark.ymlou=People. That landed in the restart window and failed silently (ldapadd || true), and JMeter then bound as users that did not exist: 69729 / 74409 / 56464BIND | 49on JE, PDB and Build in this PR's first CI run, against 3 on master. Both now wait forhealthywhere the image has a health check, still search the base entry (older images have a health check without the marker), and wait up to 5 minutes, the health check's start period.ldapadd, both check thatou=Peopleis there, and stop (compare-opendj.sh, with the container log saved) or fail the step (benchmark.yml) when it is not, so a seed that missed no longer leaves the job green.opendj-packages/opendj-docker/README.mddsreplication enableis writing to it.OPENDJ_REPLICATION_TYPE=srsthe directory server replicas are to be started one at a time, each once the previous one is healthy: each replica pushes its data (initialize-all) to the replicas connected at that moment, and one that is restarting at the end of its own first start misses the push and comes back in a bad generation ID while it reports healthy. CI has nosrsjob, so this is read, not run..github/workflows/build.yml(Docker testin both docker jobs)stop-ds, an offlineimport-ldif/rebuild-indexandstart-dsinside the container. That only worked because of this bug: with the server as PID 1,stop-dsstops the container. It now imports online, then checks thatdocker stop -t 60stops the container in under 50 s, not with exit code 137, and that the error log gained a "The Directory Server is now stopped" record (the server run in the foreground reports its shutdown only there). It then restarts the container, waits for it to be healthy, rebuilds the indexes online and checks the 10000 entries.docker runthe step waits for the.bootstrap-completemarker and checks that the error log already holds a "The Directory Server is now stopped" record. That pins the stop before the marker: the server logs the record before its JVM exits, andstop-dsreturns only onceserver.pidis gone at JVM exit.simplereplica sleeps before its firstdsreplication, and connected again once the replica logs "dsreplication enable exited with 8, trying again". The replica then has to become healthy and receive a change made on the master. Thesdsrreplica'senableis pinned the same way.replicate.shis run once more on thesimplereplica: itsenableof a base DN already replicated has to end it with exit 5, without "trying again" and without "initializing replication". That pins both that only exit 8 is tried again and that a failedenableends the script.Testing
The
Docker teststep, run locally against the released images with thisrun.shand the branch'sENV BOOTSTRAP_COMPLETE/HEALTHCHECKlaid over them:docker stop -t 60run.shofmaster(control)latestalpineThe stop-before-marker check, run locally the same way (with a longer timeout, as the bootstrap takes about 4.5 minutes under emulation): passes on this change, fails with the
stop-dsblock moved aftertouch "$BOOTSTRAP_COMPLETE".The replication retry, run locally the same way over the #1094 image: with this
replicate.shthe replica'senableexited with 8 while the master was off the network, connected on the next try, and the replica became healthy and received the change; with thereplicate.shofmaster(no retry) the replica logged "Replication setup failed" and never became healthy.The replication part of the step as it now stands (
build-dockerjob, extracted frombuild.yml, only the names and timeouts changed), run locally over the round-3 image with thisreplicate.sh: passes in 6 minutes, both disconnects included. The secondreplicate.shexits 5 on this change, and fails the check withretry anyon thesimpleenable(it tries again and runs intotimeout 90) and with its|| exitremoved (it goes on toinitializeand exits 0). Ansdsrreplica whoseenableis not wrapped inretrynever logs "trying again" while the master is off the network, and logs "Replication setup failed".The new benchmark wait, run locally followed by
ldapadd people.ldif:ou=Peoplewas there after the container became healthy both on this change (98 s) and on the releasedopenidentityplatform/opendj:latest(55 s). The old wait did not lose the entry in the one local run: the window is a race, and the CI numbers above are the failing side.Out of scope
SIGTERMis still not delivered while the bootstrap itself runs (PID 1 isbashuntil theexec), and a bootstrap interrupted halfway leavesdata/configbehind, so the next start takes the restart branch. Not verified; left for a separate issue.setup.shopens the admin port beforecreate-backend, so a replica that reaches its master during that part of the master's bootstrap gets "no suffix to replicate" rather than a connect error, which is not tried again. This predates this change (read, not run).