An apluggy plugin for cactus-client that implements admin instructions against a local Envoy server via direct database access.
When cactus-client encounters an admin_instruction step (e.g. ensure-end-device), it calls registered plugins via the cactus_client.admin hook system. This package provides the Envoy-backed implementation of those hooks.
The plugin connects directly to Envoy's PostgreSQL database. It manages its own DB connection using credentials from environment variables.
| Hook | Behaviour |
|---|---|
admin_setup |
Opens a SQLAlchemy async engine to the Envoy DB |
admin_teardown |
Disposes the engine — always runs, incl on test failure |
admin_instruction |
Handles each instruction in its own DB session with explicit commit |
Everything below assumes all three repos are cloned into the same parent directory and all commands are run from that parent directory unless noted otherwise. All commands are copy-paste ready.
workspace/ ← run all commands from here
envoy/
cactus-client/
cactus-client-envoy/
cactus-test/ ← created in step 4 (test outputs)
git clone https://github.com/bsgip/envoy.git
git clone https://github.com/bsgip/cactus-client.git
git clone https://github.com/bsgip/cactus-client-envoy.gitconda create -n cactus python=3.12 -y
conda activate cactus
pip install -e ./cactus-client
pip install -e ./cactus-client-envoyOnce cactus-client-envoy is installed, cactus-client will automatically discover and load it via the cactus_client.admin setuptools entrypoint — no code changes required.
cd envoy/demo
docker build --no-cache -t envoy:latest -f ../Dockerfile.server ../
HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose up -d
cd ../..Note: If you see encrypted key errors, your
test_certs/directory has stale certs from an older envoy version. Fix with:rm -rf envoy/demo/tls-termination/test_certs/* docker compose -f envoy/demo/docker-compose.yaml down -v cd envoy/demo && docker build --no-cache -t envoy:latest -f ../Dockerfile.server ../ && cd ../.. HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose -f envoy/demo/docker-compose.yaml up -d
cactus setup --local ./cactus-test
cactus server dcap https://localhost:8443/dcap
cactus server verify true
cactus server serca ./envoy/demo/tls-termination/test_certs/testca.crtThen run setup_clients.py to register all three demo clients. It derives LFDIs directly from the certificates:
python ./cactus-client-envoy/setup_clients.py ./envoy/demo/tls-termination/test_certsThis registers:
| ID | Cert | Type |
|---|---|---|
device1 |
testdevice1.crt |
device |
device2 |
testdevice2.crt |
device |
aggregator1 |
testaggregator.crt |
aggregator |
Copy sample.env to .env in the repo root:
cp cactus-client-envoy/sample.env cactus-client-envoy/.envThen edit .env and fill in the two values:
| Variable | Description | Example |
|---|---|---|
ENVOY_DB_DSN |
SQLAlchemy async DSN for the Envoy PostgreSQL database | postgresql+asyncpg://user:pass@localhost:8003/envoy_db |
DATABASE_URL |
Required by Envoy's model layer — use the same DSN value | postgresql+asyncpg://user:pass@localhost:8003/envoy_db |
The actual host, port, user, and password come from envoy/demo/docker-compose.yaml (see the db service).
cactus tests # list all available test procedure IDs
cactus run S_ALL_01 device1 # run a test with a single device client
cactus run S_ALL_05 device1 device2 # run a test requiring two clientsTest reports are written to ./cactus-test/.
| Variable | Description | Example |
|---|---|---|
ENVOY_DB_DSN |
SQLAlchemy async DSN for the Envoy PostgreSQL database | postgresql+asyncpg://user:pass@localhost:8003/envoy_db |
DATABASE_URL |
Required by Envoy's model layer at import time — use the same value | postgresql+asyncpg://user:pass@localhost:8003/envoy_db |
For parameter documentation see cactus-test-definitions. Envoy-specific constraints:
ensure-end-device:has_registration_link=Falseis not supported — envoy always includes a RegistrationLink. Forclient_type=aggregator, the aggregator certificate must already be registered in the Envoy DB.create-der-control: if noSiteControlGroupexists for the given primacy, one is created automatically. Scheduled controls withoutstart_offset_secondsare stacked sequentially after the latest existing end time.
Supported: ensure-end-device, create-der-control, create-default-der-control
Any Python package can provide admin hooks for cactus-client by following this pattern.
Use server_config.device_capability_uri to identify which server is under test, and read credentials from environment variables.
# pyproject.toml
[project.entry-points."cactus_client.admin"]
my-plugin = "my_package.plugin:MyServerPlugin"pip install -e .[dev,test]
pytest tests/