ci_stack#
Disposable service containers for a CI runner: start a database, wait for it to answer, remove it with its anonymous volume afterwards.
Extracted from ci_laravel.sh, which had the most complete implementation. The
point is that there is one copy: ci_laravel.sh and ci_wp_phpunit.sh each
carried their own start_database and cleanup, and the two had drifted far
enough that one guarded its EXIT trap against inherited subshells and the other
did not - a bug that removes the caller's database container mid-run.
Functions#
- ci_stack_engine_for_image
-
Purpose: Echo
mysqlorpgsqlfor a known image name. Returns 1 for an image it cannot place, so a caller refuses rather than guesses; guessing is how a container comes up and is then talked to in the wrong dialect. -
ci_stack_default_port
-
Purpose: Echo the port an engine listens on inside its container - 3306 for mysql, 5432 for pgsql.
-
ci_stack_start_database
- Purpose:
docker run -dthe image, then poll until it answers. Returns 0 when ready, 1 when it does not become ready, 2 on bad arguments. - Refuses first, by name, when docker is not on PATH. Without that the
first failure is
docker network createand the message blames the network, sending a reader after a problem they do not have. -
Options:
--imageand--nameare required.--engine(defaultmysql),--networkor--publish(see below),--db,--user,--password,--root-password,--wait-seconds(default 60). -
ci_stack_command_program
-
Purpose: Echo the program a step command would run, or nothing when the command is a shell construct. Environment prefixes are stepped over, so
DJANGO_SETTINGS_MODULE=x python manage.py testanswerspython. -
ci_stack_command_available
- Purpose: Whether that program can be run. 0 yes, 1 no.
- Arguments:
<workdir> <image-or-empty> <docker-user-or-empty> <program>. -
The probe runs with the workdir as its current directory. It did not, and a step command naming a path inside the project --
bin/thing,.venv/bin/python,vendor/bin/phpunit-- was refused before it ran, while the step itself would havecd-ed there and run it. A check that fires on correct input is worse than no check, because it gets switched off. -
ci_stack_remove
- Purpose: Remove the container and, if given, the network. Never fails: it is called from an EXIT trap, where a non-zero return would replace the script's real exit status with the cleanup's.
- Says nothing about a container that does not exist, so a failed start does not announce removing something that was never created.
- Options:
--container,--network.
Notes#
-
--networkand--publishare alternatives, not both. A caller whose steps run inside a container reaches the database by container name on a shared network; one whose steps run on the host reaches a published port. Publishing when nothing will use it fails the run with "port is already allocated" for a port nobody wanted. -
The removal uses
docker rm -f -v. The mysql and postgres images declare aVOLUME, so everydocker run -dcreates an anonymous volume; without-vthe container goes and the volume stays. Seven runs left 1.4 GB of orphaned data directories on one laptop, referenced by nothing and reported by nothing.-vremoves anonymous volumes and leaves a named one a caller supplied alone. -
--wait-seconds 0is refused. A zero wait runs the readiness loop no times and would return success against a container that has not started; a caller asking for no wait wants no database. -
An empty
--root-passwordsetsMYSQL_ALLOW_EMPTY_PASSWORD=yesrather than an emptyMYSQL_ROOT_PASSWORD, which the image rejects. Without one of the two it exits during its entrypoint, so the symptom is the readiness poll timing out with nothing about a password anywhere in the output. -
Import
loggingfor the progress and error lines.