Skip to content

bsgip/cactus-client-envoy

Repository files navigation

cactus-client-envoy

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.

How the plugin works

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

Full Setup

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)

Prerequisites

  • Python 3.12+
  • conda (recommended) or pip
  • Docker with Compose v2
  • git

1 — Clone the repos

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.git

2 — Create a Python environment and install packages

conda create -n cactus python=3.12 -y
conda activate cactus

pip install -e ./cactus-client
pip install -e ./cactus-client-envoy

Once cactus-client-envoy is installed, cactus-client will automatically discover and load it via the cactus_client.admin setuptools entrypoint — no code changes required.

3 — Build the envoy Docker image and start the demo

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

4 — Initialise cactus-client config

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.crt

Then 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_certs

This registers:

ID Cert Type
device1 testdevice1.crt device
device2 testdevice2.crt device
aggregator1 testaggregator.crt aggregator

5 — Set environment variables

Copy sample.env to .env in the repo root:

cp cactus-client-envoy/sample.env cactus-client-envoy/.env

Then 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).

6 — Run a test

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 clients

Test reports are written to ./cactus-test/.


Environment variables

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

Supported admin instructions

For parameter documentation see cactus-test-definitions. Envoy-specific constraints:

  • ensure-end-device: has_registration_link=False is not supported — envoy always includes a RegistrationLink. For client_type=aggregator, the aggregator certificate must already be registered in the Envoy DB.
  • create-der-control: if no SiteControlGroup exists for the given primacy, one is created automatically. Scheduled controls without start_offset_seconds are stacked sequentially after the latest existing end time.

Supported: ensure-end-device, create-der-control, create-default-der-control


Writing your own admin plugin

Any Python package can provide admin hooks for cactus-client by following this pattern.

1 — Depend on cactus_client

2 — Implement the hooks

Use server_config.device_capability_uri to identify which server is under test, and read credentials from environment variables.

3 — Register via setuptools entrypoint

# pyproject.toml
[project.entry-points."cactus_client.admin"]
my-plugin = "my_package.plugin:MyServerPlugin"

4 — Install alongside cactus-client


Development

pip install -e .[dev,test]
pytest tests/

About

Pluggy integration for envoy testing with cactus-client. Fires server setup/state instructions.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages