Skip to content

v0.4.0 — multi-tenant admission control, fleet standard, release hardening

Choose a tag to compare

@TadMSTR TadMSTR released this 11 Sep 23:52
· 1 commit to main since this release
94b409a

Repositions the project as multi-tenant admission control for a shared Ollama rather than a fleet pool manager, brings the repo to the fleet Baseline standard, and corrects four README claims the code did not implement.

Changed

  • Positioning. The README led with "smart pool manager for Ollama", competing on fleet routing against tools that do it better. It now leads with authenticated multi-tenant policy — priority bound to a credential and enforced server-side — which is the thing no comparable tool does: Olla has no inbound client auth at all, ollamaMQ keys priority off an unauthenticated X-User-ID header, and LiteLLM's priority is caller-declared, beta, and excludes embeddings.
  • Host state unified; hosts.py and HostManager deleted. Two structures tracked the same facts with different refresh rules and proxy.py selected through one while failing over through the other. HostManager._health_loop re-probed a host only if not host.healthy, so a host healthy at startup was never polled again and its model list was frozen for the process lifetime. RoutingTable polled correctly but was built only when routing.strategy != "round_robin" — and round_robin is the default, so the default deployment had no polling table at all. The routing table is now built unconditionally.
  • BREAKING (metric): oqp_host_models_loadedoqp_host_models_installed. The old name said "loaded" (resident in VRAM, /api/ps) and reported models merely installed on disk (/api/tags). No alias is kept.
  • HostRoutingState.loaded_modelsinstalled_models, for the same reason.
  • pick() now prefers reachable hosts on the round_robin path too, and returns a candidate rather than None when no host is reachable — a stale reachable=False should not black-hole the proxy into 503s.
  • Management endpoints check authorization before validating input. ?tier=bogus from an unauthenticated caller returned 400 enumerating the valid tiers; it now returns 401.

Added

  • key_env: and key_file: for API keys. Exactly one of key / key_env / key_file per entry. A literal in config.yml was previously the only option and not by design: _apply_env_overrides skips any path with a numeric component, so OQP_AUTH__KEYS__0__KEY was silently ignored — the list index trips it. key_file strips trailing whitespace and warns when the file is readable beyond its owner. Resolved keys carry repr=False and never appear in an error message.
  • Metadata fast path. /api/tags, /api/version, /api/ps, /api/show and / bypass the priority queue and worker semaphore (they still authenticate). Previously a UI polling /api/tags queued behind a multi-minute generation.
  • queue.max_queued_mb (default 512) — global cap on bytes waiting across all tiers. Depth limits bound the number of waiting requests; each holds its whole body until dispatch.
  • Secret scanning as a CI gate — both halves: a push/PR gate and a scheduled full-history scan with fetch-depth: 0. .gitleaks.toml had been present for months with nothing running it.
  • Release hardening. Every published architecture is now built, scanned with Trivy and smoke-tested (the container is actually started and must serve /health) before anything is pushed. Publishes multi-arch with provenance, SBOM and a signed build-provenance attestation.
  • CodeQL (python and actions), OSSF Scorecard, CODEOWNERS, Dependabot, and a committed uv.lock.
  • Ruff now carries the eight fleet-mandated rule families and lints tests/ as well as src/.

Deprecated

  • ollama.health_check_interval drove the deleted HostManager loop and is no longer read; ollama.hosts[].model_sync_interval is now the only poll interval, and it polls every host rather than only unhealthy ones. Setting it logs a warning at startup.

Documented

  • Low-tier expiry: at max_wait a queued request is not promoted — it fails with 503 {"error": "request expired in queue"} and no Retry-After.
  • The auth-off caveat: with auth.enabled: false (the shipped default and quick-start path), client_id comes from a caller-supplied header and the priority ceiling is not applied, so any client can claim any identity and any priority.
  • Model-aware routing routes on installed, not loaded, models. Where every host has the same models pulled, model_aware degenerates to weighted round-robin.
  • The proxy does not rate-limit. RateLimitConfig throttles failed authentication attempts per IP; there is no per-client request rate limit.

Conformance against the fleet Baseline: 12 pass / 6 fail → 24 pass / 0 fail / 0 skip. Tests 150 → 227; coverage 63% → 75.79% with the floor raised to 75 and CI measuring it for the first time.

Security audit: 2 findings, 1 resolved and 1 accepted. See CHANGELOG.md for the full entry.

Deploy: update ghcr.io/tadmstr/ollama-queue-proxy to 0.4.0. Existing configs load unchanged — verified against a live 11-key deployment. Note the breaking metric rename above if you scrape /metrics.