The published package is now named 'radenv' and lives under
pypi.inkbridge.io/radenv/. Script entrypoints follow the same rename:
multi-server-test{,-config} -> radenv{,-config}.
See InkbridgeNetworks/radenv@v1.0.2 for the upstream rename.
multi-server: install radenv from inkbridge pypi instead of git clone
Drop the github.com/InkbridgeNetworks/radenv.git checkout + 'make
configure' dance and install the framework as a pip package from the
inkbridge index instead. Pinned version stays in RADENV_VERSION so
bumps are a one-line change.
The inkbridge host already serves the PEP 503 simple listing at its
root, so no /simple/ suffix. --extra-index-url keeps the default
PyPI fallback for transitive deps.
Switches the python3 -m src.<module> invocations over to the
multi-server-test / multi-server-test-config entrypoints that the
sdist exposes via [project.scripts]; the cd / venv-activate dance
in front of every call goes away.
Also bumps actions/upload-artifact from v4 (Node.js 20, deprecated
2026-06-02) to v6 (Node.js 24) so ci-multi-server-tests stops
emitting the deprecation warning on every run.
profiling image: stage /docker-entrypoint.sh so it's a drop-in for service
src/tests/multi-server/environments/kafka.yml.j2 (and the other env
templates) override the Dockerfile entrypoint with a bash wrapper that
still execs /docker-entrypoint.sh. The service image stages that file
via service.{deb,rpm}.m4 but the profiling image didn't, so the
kafka-producer1 container exited 127 ("command not found") in
profiling-mode multi-server runs.
Add the same COPY + chmod to common.freeradius-profile-build.m4. Leave
the per-distro profiling.{deb,rpm}.m4 EXPOSE / CMD (sleep loop) alone
since compose overrides them anyway.
The run-index now counts at the branch/commit level instead of per
(test, mode), so a single CI invocation's parallel tests share an
index and a re-run of the same commit gets the next index.
Also swap the unicode '->' arrows in docker.mk's DOCKER_BUILD header
for plain '>' to match the BUILD echo style.
profiling image: install with --prefix=/usr to match deb/rpm layout
The profiling Dockerfile chain used the default ./configure prefix
(/usr/local), so radclient / radiusd / etc. ended up under
/usr/local/bin and /usr/local/sbin while the service image (deb/rpm
install) puts them under /usr/bin and /usr/sbin. Test fixtures had
to either drop absolute paths or branch on mode.
Pass --prefix=/usr so the source build lands binaries at the same
absolute paths as the production packages. Update the radiusd ->
freeradius alias symlink to match. Restore /usr/bin/radclient in the
proxy-accept and proxy-multihop-accept test templates now that both
modes resolve it the same way.
multi-server: invoke radclient from PATH; surface docker build log on failure
The proxy-accept and proxy-multihop-accept test templates were calling
/usr/bin/radclient directly. That path is correct for service mode
(deb-installed FR) but the profiling image builds from source with the
default ./configure prefix, so radclient lands at /usr/local/bin/radclient
and the exec failed with 'No such file or directory'. Drop the absolute
path and rely on $PATH so both modes work.
Also add the same Show-docker-build-log failure step to
ci-multi-server-tests.yml that docker-refresh / docker-crossbuild /
docker-service already have, so the apt errors from a failed
crossbuild / profiling-deps build aren't trapped in a per-job runner
log file.
scripts/docker/docker.mk: switch the PULL echo from 'latest <- registry'
to 'latest < registry' to match the BUILD echo's plain redirect style.
common.deb.dbgsym: tolerate ddebs version skew per-package
ddebs.ubuntu.com and debian-debug rebuild dbgsyms slower than the
matching main package gets a security update. On any given day a
handful of entries are in skew: dbgsym pinned to -buildN while main
is at -ubuntuN.M.K, so an apt-get install of the full list fails with
unmet dependencies. Recent refresh runs caught 9 packages mid-skew on
jammy in one snapshot.
Switch back to per-package install with a WARNING fallback. Skewed
entries are logged loudly so missing symbols stay visible, and the
remaining ~15 of ~24 dbgsyms still land. The next refresh picks up
the previously-skewed ones once ddebs catches up.
docker-refresh: build crossbuild from upstream OS, run freeradius in parallel with CI bases
process-freeradius-images was overriding crossbuild's FROM to
self-hosted-ci-<distro> via CB_FROM_* env vars to reuse the slim CI
toolchain layer. The reuse saved a minute or two of apt-install per
distro at the cost of a hard dependency on process-ci-images
(crossbuild's FROM had to exist in the registry before the build).
Drop the CB_FROM_* block so crossbuild builds from the upstream
ubuntu/debian/rocky base directly, same path service uses. Trades a
modest build-time increase for parallelism with process-ci-images
and removes the cross-job FROM-chain that broke during the
self-hosted-{deb,rocky} -> self-hosted-ci rename.
Add a workflow-level concurrency group with cancel-in-progress: false
so a second refresh trigger (push to master + a manual workflow_dispatch,
two manual triggers in quick succession, or the nightly schedule
overlapping a push) queues behind the running one instead of starting
a second parallel refresh.
cancel-in-progress is left false: an in-flight refresh that's halfway
through publishing :latest tags shouldn't be torn down by the next
trigger; let it finish, then run the queued one which re-publishes
everything cleanly.
docker-refresh: chain freeradius-images on ci-images
process-freeradius-images was running in parallel with
process-ci-images, both gated on process-docker-cli. crossbuild
FROMs self-hosted-ci-<distro>:latest and resolved that via the
previous nightly's registry copy. The rename from
self-hosted-{deb-,rocky}<distro> to self-hosted-ci-<distro> means
no previous nightly has published the new tag yet, so the parallel
crossbuild step now fails with 'manifest not found' on the FROM.
Serialise: freeradius-images needs ci-images. One extra wait per
refresh in exchange for a working FROM chain through any future
rename.
docker-refresh: rename CI bases to self-hosted-ci-<distro>, surface build log on failure
The slim CI build bases (built from scripts/docker/build/<distro>/Dockerfile.ci
and consumed by ci-deb.yml / ci-rpm.yml) were named inconsistently:
the rpm side ran as self-hosted-rocky{9,10} and the deb side as
self-hosted-deb-{debian12,debian13,debiansid,ubuntu22,ubuntu24,ubuntu26}.
Unify on self-hosted-ci-<distro> across both families. self-hosted-ubuntu24
(no -ci-) stays as the GH runner host image so the two roles are
distinguishable.
Updates the matrix entries in docker-refresh.yml, the CB_FROM_* env
in process-freeradius-images and docker-crossbuild.yml, and the
BUILD_IMAGE strings in ci-deb.yml / ci-rpm.yml.
Also re-adds the Show docker build logs failure step to
process-freeradius-images (got lost in an earlier rewrite). Without
it the actual apt errors from the dbgsym install stay hidden in
build/docker/build.<os>.profiling-deps on the runner.
docker-refresh: force bash for container-based jobs
When a GH Actions job declares a container:, the per-step run: shell
defaults to /bin/sh (dash on the cli image's debian base). The Create
build dependency package step uses $(stat -c'%u:%g' .git) inside an
unquoted heredoc, and dash fails to parse that with a cryptic
'Syntax error: "(" unexpected'. Pin shell: bash for both
process-ci-images and process-freeradius-images.
Also renames process-images to process-ci-images for clarity now
that it only covers the CI runner / build bases plus pull-through
caches.
docker-refresh: rebuild freeradius-build-deps.deb for self-hosted-ubuntu24
scripts/ci/docker/Dockerfile COPYs /freeradius-build-deps.deb and
/freeradius-build-deps-extra.deb into the runner host image. After the
matrix split the build step was orphaned in process-host-bases so the
files were never generated, and the docker build failed with a 'cache
key not found' on the COPY. Re-add the dep-pkg step in
process-host-bases, gated on a needs_build_deps flag on the ubuntu24
matrix entry.
docker-refresh: build dind + cli first, run the rest under fresh dind
Split docker-refresh into a four-stage pipeline so the freshly built
dind sidecar and docker-cli job-container are in the registry before
anything else uses them.
process-host-bases raw host, parallel: self-hosted-ubuntu24
(alias self-hosted) and self-hosted-docker-dind
process-docker-cli raw host, needs process-host-bases: builds
self-hosted-docker-cli, which FROMs self-hosted
process-images dind + cli, needs process-docker-cli, parallel:
the remaining CI bases (rocky/deb-*) plus the
mariadb / postgres / 389ds pull-through caches
process-freeradius-images
dind + cli, needs process-docker-cli, parallel:
the freeradius4-{crossbuild,profiling-deps,
service} chain per distro
Stages 3 and 4 use fresh dind + cli from this run instead of the
previous cycle's copies. Stages 1 and 2 stay on the raw self-hosted
runner because they're building the very dind/cli they'd otherwise
sit inside.
Also switches all internal-registry logins to docker/login-action@v4
for consistency with the existing Docker Hub login.
docker-refresh: parallelise jobs and fix dbgsym install terminator
Drop the needs: chain in docker-refresh.yml so process-images,
process-docker-cli and process-freeradius-images all start in
parallel. Each job's container and FROM dependencies resolve from
the previous cycle's :latest, so a one-cycle staleness is acceptable.
Rename process-derived-images to process-docker-cli since it builds
exactly one image.
Fix common.deb.dbgsym.m4 to terminate the apt-get install reliably:
move libc6-dbg to the tail as the unconditional last token. On sid
and resolute the libxml2/libidn12/python ifelse blocks all evaluate
to empty, which left the previous-to-last package's trailing
backslash joining the apt-get install command with the next RUN.
Buildkit fed "RUN git clone FlameGraph ..." to apt as a package name
and exited 100. Also corrects the codename test from forky to sid to
match Dockerfile.m4's OS_CODENAME mapping for debiansid.
Merge profiling-multi-server-fixes into developer/arr2036
Pulls in the docker-refresh, profiling-deps split, /etc/freeradius
standardisation, ddebs version-skew tolerance, and matrix display
name work from profiling-multi-server-fixes. Resolves conflicts in
docker.mk and dockerfile.mk by keeping the cleaner per-type list
factoring from developer/arr2036 and extending it with profiling-deps.
Adds display: fields to every docker-refresh.yml matrix entry so the
GH Actions UI shows the actual image identity instead of the entry
dict serialisation, renames the workflow to "Docker refresh", and
labels the FR-image chain job as
freeradius4-{crossbuild,profiling-deps,service}-<os>.
common.deb.dbgsym: tolerate apt-get update flakiness for ddebs sources
The dbgsym RUN step did `apt-get update && for pkg in ...`. When the
update step fell over - typically because ddebs.ubuntu.com or
debug.mirrors.debian.org returned a 5xx mid-fetch despite the
Acquire::Retries=3 we set in the toolchain template - the && killed
the whole RUN with exit 100 before any of the per-package installs
ran. The per-package loop already prints a WARNING and continues
for any individual package the cache can't resolve, so letting the
update itself fail soft means partial cache + best-effort installs
still happen rather than tipping the whole image build over.
Concretely: docker.profiling.ubuntu24 stopped building on the
docker-server workflow each time ddebs hiccupped, even though every
dbgsym package is technically optional and FR ships fine without
them.
redhat: install config under /etc/freeradius to match the debian layout
The RPM build used the historical /etc/raddb path while the debian
package installs to /etc/freeradius. Everything downstream that
mounts FR config (the multi-server compose files, the profiling
image's m4 macro) was already on /etc/freeradius - the RPM was the
odd one out, leaving operators of rocky9/10-derived images to deal
with a different config path than ubuntu/debian operators.
The configure call gains --with-raddbdir=%{_sysconfdir}/freeradius
so FR's compile-time raddbdir matches what the spec actually
packages. All the hardcoded %{_sysconfdir}/raddb paths in the %files
manifest and the post-install bootstrap, the systemd unit's
ReadOnlyDirectories, and the sysv init script's config_dir default
all flip to %{_sysconfdir}/freeradius / /etc/freeradius.
Operators upgrading an existing RPM install will need to move (or
symlink) /etc/raddb to /etc/freeradius before reinstall - the
%config(noreplace) entries won't migrate files across paths, and
the post-install certificate bootstrap reads from the new location.
multi-server: standardise compose mounts on /etc/freeradius
The kafka, proxy, and proxy-multihop env files mounted configs at
/etc/raddb/, while the four new accept / ldap / mysql / pap-auth env
files mounted at /etc/freeradius/. Both paths resolve to the same
underlying directory (the freeradius4-profiling image has an
/etc/raddb -> /etc/freeradius symlink configured by
common.freeradius-profile-build.m4, and the standard debian package
that backs freeradius4-service installs config under /etc/freeradius
with raddbdir pointing there), but FR's semaphore association uses
the literal path it was started with - so kafka-producer1 and the
proxy homeserver containers were associating semaphores against a
file path that didn't quite match what FR ultimately opened, tripping
ENOENT on -n-prefixed runs.
Rewrite every /etc/raddb/... bind target to /etc/freeradius/...
across all the multi-server env files (and the start_valgrind_profiling.sh
script's mount target) so the kafka and proxy suites work against
both the service image and the profiling image without per-image
divergence. ${raddbdir} references inside the rendered radiusd.conf
fragments stay as-is - that's FR's compile-time variable, not a
literal path, and it already resolves to /etc/freeradius on both
images.
ci: retarget docker prune at the internal registry, not the host daemon
The previous prune walked the runner host's docker daemon looking for
images carrying a ci-ttl label, but the entire CI pipeline builds
inside per-job DIND sidecars - those images live in dind, never on
the host daemon, and go away when each job ends. The prune ran every
30 minutes and reliably reported `removed=0 kept=0` because the place
it was looking was always empty. Meanwhile the actual disk pressure
is on the internal registry, where docker-server.yml and
docker-crossbuild.yml accumulate one freeradius4-<type>/<image>:<sha>
per commit until something cleans them up.
The new job runs inside the self-hosted-docker-cli container,
authenticates to docker.internal.networkradius.com with the
DOCKER_REPO_UPDATE_* secrets, walks the catalog for repos under the
freeradius4-* namespaces, pulls each tag's manifest + image config
to recover the ci-ttl label and creation timestamp, and issues
`DELETE /v2/<name>/manifests/<digest>` for anything past its
deadline. The label TTL semantics, log shape, and 30-minute cron
are unchanged. Disk reclamation still needs `registry
garbage-collect` to run on the registry host afterwards; that's not
in scope here.
version.sh: silence git describe stderr on branches without release/branch tags
`version.sh commit_depth` runs
`git describe --tags --match 'branch_*' --match 'release_*'`
to count commits since the last branch/release tag. On feature
branches and freshly-checked-out CI workspaces neither tag class is
reachable from HEAD, so git describe exits non-zero and emits
"fatal: No names found, cannot describe anything." to stderr. The
existing `|| echo "${commit_depth}"` fallback already covers the
exit code; redirect stderr to /dev/null on the git describe call so
the message stops leaking into CI build logs (it was showing up
twice per docker-server.yml step plus once inside the in-container
`make deb`).
ci: docker prune script logs the actual image being pruned
The remove / skip lines used to identify the image by sha256 hash
only, which is useless when you're trying to figure out which build
of which type just disappeared at 02:14am. Pull the docker inspect
output forward to include {{join .RepoTags ","}} and render each
decision as `<repo:tag,repo:tag,...> (sha256:first-19-chars)`.
Falls back to "<dangling>" when RepoTags is empty (orphaned cache
layers). Added a corresponding keep line so the log shows the full
picture of what the prune considered each pass, not just the
deletions, and surfaced the parsed ci-ttl value in each message so
the cron / TTL pairing is visible without cross-referencing the
labels yourself.
ci: re-add nightly schedule trigger to multi-server
Restore the nightly cron entry that was lost when the workflow was
narrowed to workflow_run-only. The schedule path runs the full
multi-server test set instead of the per-commit CI subset (the
original split before the gating change). It fires independently of
the upstream Docker crossbuild images workflow, so the matching
crossbuild image may not be in the internal registry at trigger time
(e.g. after a registry prune) - docker.mk's stamp dependency chain
handles that: a pull-through miss on the crossbuild image cascades
into a local crossbuild docker build via the existing fallback
branch, then the profiling layer is built on top. Slow path but
self-sufficient.
The job-level if: gate now lets schedule events through (the prior
workflow_run.conclusion check would have skipped them). The checkout
ref: falls back to github.sha when event.workflow_run.head_sha is
unset (schedule has no upstream workflow_run context). The test
command split keys on matrix.mode + event_name so service / profiling
each get the full target on schedule and the .ci suffix otherwise.
ci: rename docker / crossbuild workflows to reflect what they publish
docker.yml -> docker-server.yml ("Docker service images") and
crossbuild.yml -> docker-crossbuild.yml ("Docker crossbuild images")
so the workflow names match the freeradius4-<type>/<image>:<sha>
namespaces they push to the internal registry. The workflow_run
trigger in ci-multi-server-tests.yml, the failure-diagnosis filter
in claude-ci-failure-diagnosis.yml, and the comment refs in
docker-refresh.yml all updated to the new names.
The dead `if [ "\$GITHUB_EVENT_NAME" = "schedule" ]` branches in the
multi-server test step are gone too; multi-server is now
workflow_run-only, so the schedule case never fires.
ci: multi-server tests trigger via Check Crossbuild only
Drop the push / pull_request / schedule / workflow_dispatch triggers
left over from the previous shape. Each of them would race ahead of
Check Crossbuild and find no freeradius4-crossbuild/<image>:<sha> in
the internal registry to consume, falling all the way back to a
local rebuild and defeating the whole pull-through chain.
workflow_run is now the only entry point. The job-level if: gate
simplifies to a straight conclusion == 'success' check and the
checkout step pins straight to event.workflow_run.head_sha without
the prior fallback for the now-deleted triggers.
ci: chain multi-server tests after crossbuild and use push-capable creds
The push steps in crossbuild.yml + docker.yml reused the existing
DOCKER_REPO_USERNAME / DOCKER_REPO_PASSWORD secrets, which only carry
read access to docker.internal.networkradius.com (enough for pulling
the self-hosted base images). Each push 401'd against nginx with
"Authorization Required". Both workflows now do a second docker login
right before the push using DOCKER_REPO_UPDATE_USERNAME /
DOCKER_REPO_UPDATE_PASSWORD, which override dind's auth config for the
upload only - the earlier read-only login remains for the pull paths.
ci-multi-server-tests.yml now fires off Check Crossbuild completion
via workflow_run instead of on every push. The job skips when the
upstream crossbuild run didn't succeed (workflow_run.conclusion gate),
and the checkout pins to the SHA the crossbuild run was triggered
against (event.workflow_run.head_sha) so the multi-server pass tests
the same commit the crossbuild image was built from. PR / schedule /
manual dispatch triggers are untouched.
multi-server: switch ldap suite to dinkel/openldap
osixia/openldap fights docker bind-mounts at every granularity: its
slapd-bootstrap chowns the LDIF mount on startup (fails read-only),
post-init rms the parent dir (fails when the dir is bind-mounted),
and runs `sed -i` on the LDIF via a temp-file rename (fails on a
file-level bind-mount because rename can't replace the target). No
mount shape survives all three rewrites without baking the LDIF into
a derived image.
dinkel/openldap reads `/etc/ldap/prepopulate/*.ldif` and slapadds them
once on first start, never touching the mount. The image takes
SLAPD_DOMAIN / SLAPD_PASSWORD via env, listens on the default port
389, and our existing configs/openldap/bootstrap/01-testuser.ldif
works as-is. Healthcheck uses bash's /dev/tcp because dinkel doesn't
ship ldap-utils.
multi-server: use \$PROFILING not \${PROFILING} in test templates
radenv's events/CommandEvents.run_command runs every shell snippet
through a `\${name}` -> `<project>-<name>-1` regex before docker exec,
treating any \${...} as a container reference. That silently rewrote
our profiling-mode branch's `if [ "\${PROFILING}" = "yes" ]` to a
container-name comparison, always taking the non-profiling branch and
running freeradius without valgrind. Bash accepts the unbraced
\$PROFILING form and the radenv regex doesn't match it.
With this in place test.multi-server.profiling.ci produces real
callgrind output (~21 per-thread files per suite) for all four new
suites.
util: make libbacktrace recipe a grouped target and use a relative HEADERS path
libfreeradius-util.mk drove libbacktrace via a regular two-target rule
that called the libbacktrace sub-make. GNU make >=4.3 expands a
multi-target rule as one independent rule per target sharing the same
recipe text, so parallel make can schedule the recipe twice when both
outputs are needed in the same invocation. Two concurrent sub-makes
land in the same .a / .libs/ directory; ar mid-writing libbacktrace.a
(with mmapio.o as a member) while a peer ranlib reads it surfaces as
"ranlib: .libs/libbacktrace.a: error reading mmapio.o: file truncated"
under -j>1. The grouped-target form (`&:`, added in GNU make 4.3) tells
make a single recipe invocation produces both outputs and only
schedules it once.
The HEADERS entry for backtrace.h was `$(top_srcdir)/.../backtrace.h`.
The install rule does `$(addprefix ${SRC_INCLUDE_DIR}/,$(HEADERS))`,
so an absolute path produces a double-slash install target like
`${SRC_INCLUDE_DIR}//abs/path/backtrace.h`. The pattern rule
`${SRC_INCLUDE_DIR}/%.h: src/include/%.h` still matches that target,
but its derived prereq `src/include//abs/path/backtrace.h` doesn't
exist, so `make install` fails with "No rule to make target". This
breaks every build where $(top_srcdir) resolves to an absolute path,
i.e. inside docker builds where @abs_top_srcdir@ is /usr/local/...
The relative `backtrace/backtrace.h` form reaches the same file via
the src/include/backtrace -> ../lib/backtrace symlink set up just
below.
build,profiling-image: gate dsymutil on apple-darwin so libbacktrace links survive ELF
scripts/boiler.mk:702 used to set DSYMUTIL = $(shell which dsymutil)
whenever AC_HAVE_BACKTRACE was set, with no target-platform check.
On Linux that picked the LLVM dsymutil up off PATH (now reliably
present in the profiling image because kcachegrind/inferno pull in
the LLVM toolchain), and jlibtool then invoked it against every
linked .so. dsymutil only understands Mach-O, so the first link of
libfreeradius-make-dlopen.so under -g3 aborted with "cannot parse
the debug map for build/lib/.libs/libfreeradius-make-dlopen.so:
The file was not recognized as a valid object file" and the make
plugin's recursive build never produced the .so the parent make
tried to load. Restricting the binary lookup to apple-darwin
TARGET_SYSTEM falls back to the existing `DSYMUTIL := echo` no-op
on every other platform, so the recipe step stays harmless.
scripts/docker/m4/common.freeradius-profile-build.m4 now wipes any
host build artefacts that survived the COPY before invoking
autoconf/make so the container builds from a clean state. The
libbacktrace submodule in particular tends to carry host-absolute
paths in its generated Makefile / libtool, which broke the
in-container configure when the host tree had been built natively
on a different architecture.
multi-server: dedup load-generator-packets across all suites and ignore host build/
The proxy / proxy-multihop / kafka suites all carried their own copy of
the same load-generator packet.conf, byte-identical to what the new
accept/ldap/mysql/pap-auth suites now read from configs/freeradius/
common/proto-load/. Drop the per-suite copies and repoint the compose
envs at the shared one. The unused common/proto-load/template.d
placeholder is removed (no radiusd.conf.j2 or env mount referenced it).
.dockerignore now also excludes the local build/ and prof-results/
directories so docker builds that do `COPY . .` don't drag a polluted
host tree into the image and confuse in-container Makefile installs
with absolute host paths.
multi-server: dedup proto_load scaffolding into common/proto-load
The proto_load packet config, stats placeholder, packet template
fragment, and load-generator-packets/packet.conf were byte-identical
across accept/ldap/mysql/pap-auth. Lift them to configs/freeradius/
common/proto-load/ and point each suite's compose env at the common
mount path. A one-line change to the load profile now touches one file
instead of four.
multi-server: fold profiling into standard suites with a MODE matrix
Renames prof-accept/prof-ldap/prof-mysql/prof-pap-auth to accept/ldap/
mysql/pap-auth so they sit alongside proxy-accept and kafka-produce as
ordinary multi-server suites. Each suite is now driven once with MODE=
service (default, freeradius-build:latest, exec the server directly)
and once with MODE=profiling (freeradius-prof:latest, source the
valgrind/callgrind wrapper). The compose envs reference
${FREERADIUS_IMAGE} and ${PROFILING}, and the per-test recipe in
all.mk exports those alongside PROF_RESULTS_PATH based on MODE. The
bespoke Dockerfile.multi-server-prof and the build_image.sh /
run_container.sh wrappers are gone; the standard
freeradius4-profiling/<image>:<sha> image (with FreeRADIUS now compiled
in by common.freeradius-profile-build.m4) is just re-tagged as
freeradius-prof:latest by the new freeradius-prof.image target.
ci-profiling.yml is deleted; ci-multi-server-tests.yml grows a
matrix.mode = [service, profiling] so both passes share one job
template, one set of dind/cli images, and one workflow_dispatch entry.
The mariadb fixture now loads the canonical schema from
raddb/mods-config/sql/main/mysql/schema.sql via an additional ordered
mount and only seeds the testuser row locally; the openldap fixture
switched to osixia/openldap:1.5.0 plus an LDIF bootstrap; mariadb data
moved to tmpfs so init.sql re-applies on every compose-up.
Pulled in via merge from marc-casavant/profiling-multi-server-tests, then
addressed the structural and bug review feedback before the larger suite
restructure: the bogus crossbuild.ubuntu24.profile.* and docker.openldap.prof
target references in all.mk are gone, the multi-server prof Dockerfile now
FROMs the standard freeradius4-profiling/ubuntu24 image via build-arg, and
the configure/make/install pass with callgrind-friendly CFLAGS is lifted
into a shared common.freeradius-profile-build.m4 so every distro's
Dockerfile.profiling produces an image with FreeRADIUS already installed.
Bug fixes in start_valgrind_profiling.sh: VALGRIND_PID now captures the
valgrind process (was tee, leaving the fallback kill paths hitting the
wrong PID), the dead PROFILE_DURATION string-arithmetic line is removed,
and the eval-wrapped callgrind_annotate call is replaced with a direct
invocation. 5min.test.yml files now use test_verify_timeout to match the
template (was test_state1_verify_timeout, undefined). prof-ldap/prof-mysql
no longer mount mods-config/files/authorize, neither config loads files.
README path under scripts/profiling/ corrected. Openldap fixture switched
to osixia/openldap:1.5.0 with an LDIF bootstrap under
configs/openldap/bootstrap/ instead of the missing docker.openldap.prof
target.
WIP: CI profiling workflow is now split into two jobs; build-profiling-image to build profiling images and push to docker registry, profiling-tests that pulls images from registry and runs tests.
docker: drive per-type wiring from a single TYPES list
docker.mk and dockerfile.mk both had a hand-written stanza per type:
four DOCKER_BUILD calls, four DOCKERFILE_RULE calls, four umbrellas.
Adding a fifth type meant editing every block. Collapse them into a
single DOCKER_TYPES / DOCKERFILE_TYPES list plus a double foreach over
images and types.
Per-type quirks (profiling's --build-arg=from=crossbuild and crossbuild
stamp dependency, the optional CB_FROM_$(IMG) override on crossbuild)
move into DOCKER_BUILD_ARGS_<type> / DOCKER_BUILD_DEPS_<type> recursive
variables, so the $(IMG) inside them resolves at the right point in the
foreach. Adding a new type is now: append to the list, drop in the m4
files, optionally set the two lookup vars.
docs-v4: update howto/modules/CHAP for v4, added diagram, and separated doc
into pages for increased readability.
Formatting, typo, and nav fixes (2nd commit).
ci: surface the docker build log when docker.yml fails
DOCKER_BUILD redirects buildkit output to build/docker/build.<image>.<type>
to keep parallel builds from interleaving on stdout. When CI fails,
the workflow log shows the BUILD echo then several silent minutes
followed by Post job cleanup, with no clue what broke. Add an
if-failure cat step in both job variants so the underlying error
surfaces in the run page.