Skip to main content

Local LXC/Incus container management for chatmail relay development and testing

Project description

cmlxc -- local chatmail container management and testing

Manage local Incus containers for chatmail relay development and testing.

cmlxc spins up lightweight LXC containers, deploys chatmail relay services into them via cmdeploy or madmail, and runs integration tests -- all without touching the host system.

Architecture

cmlxc manages four kinds of containers, each with a distinct role:

    cmlxc init / deploy-* / test-*
        |
        v
   +-----------------+   +------------------------+   +--------------------+
   | ns-localchat    |   | builder-localchat      |   | relay containers   |
   | (PowerDNS)      |   | (repos, venvs, builds) |   | (cm0, mad1, ...)   |
   +-----------------+   +------------------------+   +--------------------+
           ^                        |                           ^
           |      DNS zones         |        SSH / SCP          |
           +------------------------+---------------------------+

Base image (localchat-base) -- A Debian 12 image with SSH and Python pre-installed. All other containers are launched from this image (or from a cached relay image).

DNS container (ns-localchat) -- Runs PowerDNS authoritative + recursor. Provides .localchat DNS resolution so containers can reach each other by name.

Builder container (builder-localchat) -- The central workhorse. Holds repository checkouts (/root/relay, /root/madmail), Python virtualenvs for cmdeploy and mini-tests, and the compiled maddy binary. All deployment and test operations are executed inside the builder -- the host only needs cmlxc itself.

Relay containers (e.g. cm0-localchat, mad1-localchat) -- Ephemeral containers that receive a deployed chatmail service. Each relay is locked to a single deployment driver (cmdeploy or madmail); switching requires destroying and re-creating the container.

Deployment drivers

Drivers live in driver_cmdeploy.py and driver_madmail.py. Each driver has an init_builder() function (called during cmlxc init) and a deploy() function (called during cmlxc deploy-*).

  • cmdeploy -- Runs cmdeploy run from the builder container over SSH into the relay. Generates DNS zones, loads them into PowerDNS, and verifies records. After the first successful deploy the relay image is cached as localchat-relay so subsequent containers start pre-populated.

  • madmail -- Builds the maddy Go binary on first deploy (the triggered make is idempotent on reruns), then pushes it via SCP and runs madmail install --simple --ip <IP>. No DNS entries are needed.

Prerequisites

Incus installed and configured on the host. Usually only being part of the "incus" group is neccessary, as containers can run with user priviledges.

Installation

With pip:

python -m venv venv
source venv/bin/activate
pip install .

Or with uv:

uv venv venv
source venv/bin/activate
uv pip install .

Usage

Initialize the environment (base image, DNS container, builder container):

cmlxc init

Use --relay-repo or --madmail-repo to sync a local checkout instead of cloning from GitHub:

cmlxc init --relay-repo ../relay --madmail-repo ../madmail

Deploy chatmail relays (creates containers if needed, then deploys):

cmlxc deploy-cmdeploy cm0 cm1
cmlxc deploy-madmail mad1
cmlxc deploy-madmail --ipv4-only mad1

Run integration tests inside the builder:

cmlxc test-mini cm0
cmlxc test-mini cm0 cm1          # cross-relay tests
cmlxc test-cmdeploy cm0 cm1

SSH into a deployed relay:

ssh -F ~/.config/cmlxc/ssh-config cm0

Lifecycle commands:

cmlxc status                # show all containers
cmlxc start cm0             # restart a stopped relay
cmlxc stop cm0 cm1          # stop relays
cmlxc destroy cm0           # stop + delete
cmlxc destroy --all         # destroy relays, keep DNS/builder
cmlxc destroy --reset       # full teardown, requires re-init

Increase verbosity with -v or -vv:

cmlxc deploy-cmdeploy -vv cm1

Shell Completion

cmlxc supports Bash tab-completion for subcommands, options, and container names.

Enable for the current session:

eval "$(register-python-argcomplete cmlxc)"

Enable permanently:

activate-global-python-argcomplete --user

Releasing

Versions are derived from git tags via setuptools-git-versioning. The changelog is generated with git-cliff using the cliff.toml config in the repo root.

Steps

  1. Preview unreleased changes:

    git cliff --unreleased
    
  2. Tag the release (the tag name becomes the version):

    git tag v0.1.0
    
  3. Generate the full changelog:

    git cliff -o CHANGELOG.md
    
  4. Amend the tag commit to include the changelog:

    git add CHANGELOG.md
    git commit --amend --no-edit
    git tag -f v0.1.0
    
  5. Push tag and branch:

    git push origin main --tags
    

The release.yml GitHub workflow triggers on pushed v* tags, builds the sdist + wheel, and publishes to PyPI via trusted publishing (OIDC).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cmlxc-0.5.0.tar.gz (31.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cmlxc-0.5.0-py3-none-any.whl (31.7 kB view details)

Uploaded Python 3

File details

Details for the file cmlxc-0.5.0.tar.gz.

File metadata

  • Download URL: cmlxc-0.5.0.tar.gz
  • Upload date:
  • Size: 31.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for cmlxc-0.5.0.tar.gz
Algorithm Hash digest
SHA256 376d5a3f8b503a0542fd0cb497bee4a3da5e4870477a8299f0c062e7413f7178
MD5 b3e8ef4ef598b4e9a8af4e4c2b287b5f
BLAKE2b-256 1e6ddcb7cdac3568379b6aed86d23a92642d26c9fc333ec69b1ce463eba331bd

See more details on using hashes here.

File details

Details for the file cmlxc-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: cmlxc-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 31.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for cmlxc-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1ef4c9783dfccd03e139437a9dfd578b2de171eb9671deed9917a5b6e7e48391
MD5 6fbe4834ac5f7fc236ca9b4a40f8fd7b
BLAKE2b-256 2dfd9440dcd3b229cf5d078dee4ca81f3bfe5a79e21ad3444a3f1acdc4c6c896

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page