Skip to content

luxfi/operator

Repository files navigation

Lux Operator (Go)

Go-language parity operator for the Lux platform. Sibling to hanzoai/operator (Rust, canonical for all universes); same CRDs, same reconcile behavior, different language.

Used by:

  • lux.cloud production (single Go-binary stack for the Lux universe).
  • The lux community where the Go ergonomics fit existing services.

The canonical Rust operator (hanzoai/operator v0.2.3+) continues to run in production for all four universes (hanzo, lux, zoo, osage); this Go port exists so the Lux community can extend the operator in Go natively without the Rust toolchain in their critical path.

Architecture

Property Value
Language Go 1.26
Framework sigs.k8s.io/controller-runtime 0.23
Image ghcr.io/luxfi/operator:vX.Y.Z (semver only, never :latest)
API group Configurable at install via --api-group / OPERATOR_API_GROUP (default lux.cloud)
Default namespace hanzo-operator-system

CRD Kinds (20 canonical + 3 legacy compat)

Canonical v1

Kind Short Materializes
Service hsvc Deployment + Service + Ingress + HPA + PDB + NetworkPolicy + KMSSecret
Datastore hds StatefulSet + ClusterIP Service + headless Service + PVC + aliases
Gateway hgw Deployment + Service + ConfigMap (krakend.json) + Ingress
MPC hmpc StatefulSet + headless + ClusterIP Service
Network hnet StatefulSet (validators) + Services + PVC
Ingress hing Multiple Ingress resources with cert-manager TLS
DNS hdns Deployment + Service (CoreDNS)
BaseApp bapp StatefulSet + headless + ClusterIP Service (Quasar writer election)

Facades v1 (delegate to Service/Datastore)

Kind Short Inner
SQL sql Datastore (type=postgresql)
KV kv Datastore (type=valkey)
DocDB docdb Datastore (type=docdb)
S3 s3 Datastore (type=minio)
IAM iam Service
KMS kms Service
LLM llm Service
Indexer idx Service
Explorer exp Service

Network sub-resources v1 (NoOp stubs — parent Network builds artifacts)

Kind Short
Chain chain
Subnet subnet
Validator val

Legacy compat v1alpha1 (delegate to v1 reconcilers)

Kind Inner
HanzoService Service
HanzoDatastore Datastore
HanzoDNS DNS

CRs authored before the canonical v1 split (HanzoService, HanzoDatastore, HanzoDNS) keep working unchanged — they're aliases that delegate to the new reconcilers.

Layout

api/
  v1/                     # Canonical types (20 Kinds).
  v1alpha1/               # Legacy compat types (3 Kinds).
cmd/
  operator/main.go        # Manager entrypoint.
  generate-crd-yaml/      # Per-universe CRD bundle generator.
internal/
  apply/                  # Server-side apply helper.
  controller/             # One reconciler per Kind + ReconcileServiceSpec /
                          #   ReconcileDatastoreSpec shared paths.
  manifests/              # Pure K8s object builders (no I/O).
config/
  crd/bases/<group>/      # Pre-rendered CRD YAML per universe.
  default/                # RBAC + ServiceAccount + Deployment + Namespace.
Dockerfile                # Multi-stage build → distroless static.

Build / Test / Run

go build ./...                                    # build
go vet ./...                                      # vet
go test -race ./...                               # unit tests
go run ./cmd/operator --api-group lux.cloud       # local run against current
                                                  # kubeconfig

Generating CRD bundles per universe

The same operator binary serves every universe; bake the API group into the CRD bundle at install time:

go run ./cmd/generate-crd-yaml --api-group lux.cloud   --out config/crd/bases/lux.cloud
go run ./cmd/generate-crd-yaml --api-group hanzo.ai    --out config/crd/bases/hanzo.ai
go run ./cmd/generate-crd-yaml --api-group zoo.cloud   --out config/crd/bases/zoo.cloud
go run ./cmd/generate-crd-yaml --api-group osage.cloud --out config/crd/bases/osage.cloud

23 CRDs per universe (20 canonical + 3 legacy).

Install (kind / cluster)

# 1. Install CRDs.
kubectl apply -f config/crd/bases/lux.cloud/

# 2. Install operator (namespace + ServiceAccount + ClusterRole +
#    ClusterRoleBinding + Deployment).
kubectl apply -k config/default/

To run in a different universe, edit config/default/rbac.yaml to swap apiGroups: [lux.cloud][hanzo.ai] (etc.), edit config/default/deployment.yaml OPERATOR_API_GROUP env, and apply the matching CRD bundle.

Critical invariant

spec.env / spec.envFrom / spec.volumes / spec.volumeMounts MUST be honored on every generated Deployment. The gateway 503 root cause (May 2026 on the legacy Go operator) was these silently being dropped. Tests assert the round-trip:

go test ./internal/controller -run TestReconcileServiceSpec_GatewayEnvVolumesHonored

Parity contract — operator-e2e

Both this Go operator and the canonical Rust operator at hanzoai/operator must pass the operator-e2e parity suite (31 cases, 11 full-quality byte-asserted). Each cases/<id>/input.yaml + expected/*.yaml pair specifies "given this CR, the operator MUST produce these K8s objects."

# From hanzoai/universe checkout:
cd test/operator-e2e
./runners/run.sh --operator=go        # this Go operator
./runners/run.sh --operator=rust      # canonical Rust operator at hanzoai/operator

Drift between the two is a bug to fix on whichever side strayed.

Predecessor

The Rust v0.3.x implementation of this repo (pre-2026-05-18) is preserved on the legacy/rust-impl-before-go-rewrite branch. The canonical Rust operator at hanzoai/operator absorbed that codebase's CRDs (Network, Chain, Validator, Subnet, MPC, Gateway, Indexer, Explorer) when this Go port took over the main branch.

Rules

  • Go 1.26. Update via go.mod only, never via replace directives.
  • Never :latest, :main, :dev. Pin vX.Y.Z per semver-only policy.
  • Field-for-field wire compatibility with the Rust operator — CRs in the cluster MUST NOT need editing when you switch the operator binary.
  • Honor spec.env/volumes/volumeMounts — the load-bearing assertion.
  • amd64 only (arm64 paused per global LLM.md 2026-04-27 — DOKS has no arm64).

About

Kubernetes operator for Lux Network

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors