Skip to main content

Kubernetes operator that creates SIP call Jobs via a FastAPI HTTP API

Project description

mypy and pytests BuildAndPushMultiarch black-lint Cumulative Clones Docker Pulls PyPI

Gemini_Generated_Image_23m8jo23m8jo23m8_250x250.png

WIP !!!!!

sipstuff-k8s-operator

A Kubernetes operator that exposes a FastAPI HTTP API for creating SIP call Jobs. It accepts call requests via POST /call, builds Kubernetes Jobs that run sipstuff.cli call, and tracks job status.

API Endpoints

Method Path Description
POST /call Create a K8s Job that executes a SIP call
GET /jobs List all SIP call jobs
GET /jobs/{name} Get status of a specific job
GET /health Liveness / readiness probe

Quick Start

# Install dependencies (creates a Python 3.14 venv)
make install

# Run the operator locally (starts uvicorn on :8080)
python -m sipstuff_k8s_operator

# Test K8s API connectivity only
python -m sipstuff_k8s_operator conntest

Create a call:

curl -X POST http://localhost:8080/call \
  -H "Content-Type: application/json" \
  -d '{"dest": "+4912345678", "text": "Hello from sipstuff"}'

List jobs:

curl http://localhost:8080/jobs

Check health:

curl http://localhost:8080/health

Configuration

All settings are read from environment variables. Every variable is optional with sensible defaults.

Variable Default Description
JOB_NAMESPACE Downward API namespace or "sipstuff" K8s namespace for created jobs
JOB_IMAGE "xomoxcc/somestuff:latest" Container image for SIP call jobs
SIP_SECRET_NAME "sip-credentials" K8s Secret name for default SIP credentials
JOB_TTL_SECONDS 3600 TTL in seconds after job completion before cleanup
JOB_BACKOFF_LIMIT 0 Number of retries before marking a job as failed
JOB_HOST_NETWORK "true" Use host networking for SIP/RTP
PORT 8080 HTTP listen port
PIPER_DATA_DIR null Host path for Piper TTS model cache; mounted at /data/piper
WHISPER_DATA_DIR null Host path for Whisper STT model cache; mounted at /data/whisper
RECORDING_DIR null Host path for call recordings; mounted at /data/recordings
RUN_AS_USER null UID to run the job container as
RUN_AS_GROUP null GID to run the job container as
FS_GROUP null fsGroup for the job pod security context

Kubernetes Deployment

Manifests are provided in the k8s/ directory:

# Create namespace
kubectl apply -f k8s/namespace.yaml

# Create RBAC (ServiceAccount, Role, RoleBinding)
kubectl apply -f k8s/rbac.yaml

# Create the SIP credentials secret (copy and edit the example first)
cp k8s/secret.yaml.example k8s/secret.yaml
# edit k8s/secret.yaml with your SIP credentials
kubectl apply -f k8s/secret.yaml

# Deploy the operator
kubectl apply -f k8s/deployment.yaml

# Expose via ClusterIP service (80 -> 8080)
kubectl apply -f k8s/service.yaml

The operator Deployment uses liveness and readiness probes against /health, runs as a single replica on port 8080, and uses a dedicated sipstuff-operator ServiceAccount with RBAC permissions for batch/jobs and pods.

Call Request Body

POST /call accepts a JSON body with the following fields. Exactly one of text or wav must be provided.

Field Type Default Description
dest string (required) Destination phone number or SIP URI
text string null Text to speak via TTS (mutually exclusive with wav)
wav string null Path to a WAV file to play (mutually exclusive with text)
sip_server string null SIP server override
sip_port integer null SIP port override (1-65535)
sip_user string null SIP username override
sip_password string null SIP password override
sip_transport string null Transport protocol: "udp", "tcp", or "tls"
sip_srtp string null SRTP mode: "disabled", "optional", or "mandatory"
sip_tls_verify boolean null TLS server certificate verification
stun_servers string null Comma-separated STUN servers
ice_enabled boolean null Enable ICE for NAT traversal
turn_server string null TURN relay server (host:port)
turn_username string null TURN auth username
turn_password string null TURN auth password
turn_transport string null TURN transport: "udp", "tcp", or "tls"
keepalive_sec integer null UDP keepalive interval in seconds (0-600)
public_address string null Public IP address for SDP/Contact headers
timeout integer 60 Call timeout in seconds (1-600)
pre_delay float 0.0 Delay before call in seconds (0-30)
inter_delay float 0.0 Delay between WAV repeats in seconds (0-30)
post_delay float 0.0 Delay after call in seconds (0-30)
repeat integer 1 Number of call repetitions (1-100)
tts_model string null TTS model name
tts_sample_rate integer null TTS sample rate in Hz (0-48000)
tts_data_dir string null TTS data directory
verbose boolean false Enable verbose logging in the call job

SIP Credentials

SIP connection parameters can be provided per-request in the call body (sip_server, sip_port, sip_user, sip_password, sip_transport, sip_srtp, sip_tls_verify). When a field is not provided, the operator falls back to the K8s Secret specified by SIP_SECRET_NAME (default: sip-credentials).

The secret should contain these keys:

stringData:
  SIP_SERVER: "sip.example.com"
  SIP_PORT: "5060"
  SIP_USER: "sipuser"
  SIP_PASSWORD: "changeme"
  SIP_TRANSPORT: "udp"
  SIP_SRTP: "disabled"
  # SIP_TLS_VERIFY_SERVER: "false"

See k8s/secret.yaml.example for a complete example.

NAT Traversal

NAT traversal settings (STUN, ICE, TURN, keepalive, public address) can be provided per-request or configured globally via the same K8s Secret. Add any of these optional keys to the sip-credentials Secret:

stringData:
  # SIP_STUN_SERVERS: "stun.l.google.com:19302"
  # SIP_ICE_ENABLED: "false"
  # SIP_TURN_SERVER: "turn.example.com:3478"
  # SIP_TURN_USERNAME: ""
  # SIP_TURN_PASSWORD: ""
  # SIP_TURN_TRANSPORT: "udp"
  # SIP_KEEPALIVE_SEC: "0"
  # SIP_PUBLIC_ADDRESS: ""

When turn_server is provided in a request, SIP_TURN_ENABLED=true is automatically set on the job.

Development

make lint           # Black formatter (line length: 120)
make isort          # Sort imports
make tcheck         # MyPy type checking (strict mode)
make tests          # Run pytest
make prepare        # Run tests + commit-checks
make commit-checks  # Run all pre-commit hooks
make gitleaks       # Scan for secrets

Run a single test:

source .venv/bin/activate && pytest tests/test_base.py::test_version_exists -v

Initial Setup (GitHub + Docker Hub)

The repo_scripts/initial_setup_github_dockerhub.sh script automates first-time project setup:

  1. Creates the Docker Hub repository (if no OAT exists yet)
  2. Creates a scoped Organization Access Token (OAT) with push+pull for the target repo
  3. Validates that the OAT actually has push+pull access via check_dockerhub_token.py
    • If permissions are missing, offers to create a new OAT with the correct scopes
  4. Ensures the Docker Hub repo exists (handles both public and private repos)
  5. Creates a GitHub repo and a public gist for clone tracking badges
  6. Sets all required GitHub Actions secrets (DOCKERHUB_TOKEN, DOCKERHUB_USERNAME, GIST_ID, GIST_TOKEN, REPO_PRIV_TOKEN)

Configuration is read from repo_scripts/include.local.sh (not checked in). See repo_scripts/include.sh for the variable template.

# Run the setup
./repo_scripts/initial_setup_github_dockerhub.sh

Docker

# Build the image
make build
# or
docker build -t sipstuff-k8s-operator:latest .

# Run locally
docker run --rm -p 8080:8080 sipstuff-k8s-operator:latest

The image is based on python:3.14-slim and runs python3 -m sipstuff_k8s_operator as its entrypoint.

License

This project is licensed under the LGPL where applicable/possible — see LICENSE.md. Some files/parts may use other licenses: MIT | GPL | LGPL. Always check per‑file headers/comments.

Authors

  • Repo owner (primary author)
  • Additional attributions are noted inline in code comments

Acknowledgments

  • Inspirations and snippets are referenced in code comments where appropriate.

⚠️ Note

This is a development/experimental project. For production use, review security settings, customize configurations, and test thoroughly in your environment. Provided "as is" without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. Use at your own risk.

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

sipstuff_k8s_operator-0.0.4.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

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

sipstuff_k8s_operator-0.0.4-py3-none-any.whl (21.2 kB view details)

Uploaded Python 3

File details

Details for the file sipstuff_k8s_operator-0.0.4.tar.gz.

File metadata

  • Download URL: sipstuff_k8s_operator-0.0.4.tar.gz
  • Upload date:
  • Size: 18.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Hatch/1.16.3 cpython/3.14.3 HTTPX/0.28.1

File hashes

Hashes for sipstuff_k8s_operator-0.0.4.tar.gz
Algorithm Hash digest
SHA256 568e83360b950e7095b705cc1ae1b371f6b9f569b871879580a6d13d1ce40e4f
MD5 0da3cdfc594e389b19a353e248aa40ac
BLAKE2b-256 8a9d0024d14ce5aafe75af8c72bbaccfec890fc21641d5541c48a603199bb8f8

See more details on using hashes here.

File details

Details for the file sipstuff_k8s_operator-0.0.4-py3-none-any.whl.

File metadata

File hashes

Hashes for sipstuff_k8s_operator-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 d3830d195d302e16086e938ce643050263dcbd09bd3c1043dea1054e6edc4b78
MD5 cbd6d91bb3e15172fa9f66113a03b0ed
BLAKE2b-256 b90c3702ac3ee43627ee3f5772f16acad01290df31f75fca8dc77413081c4994

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