playpen-operator

command
v0.1.20-rc.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 17 Imported by: 0

README

playpen-operator

playpen-operator serves the aggregated Kubernetes API for playpen runner pods. It runs next to a pool of playpen-runner pods and allocates one idle runner to a client that presents a WireGuard public key.

The operator maintains the runner pod pool itself. It assigns each runner a unique WireGuard UDP hostPort, and on alloc patches the selected pod with the client key and returns the endpoint, network, VXLAN, and Redfish details needed to use the playpen VM.

The returned guest network metadata is intended for a VM whose default gateway is configured on the client side of the tunnel. The runner pod exposes only the VM's L2 path into VXLAN; VM egress is routed and NATed by the client tunnel namespace.

The same runner image is also used for pooled k3s control-plane pods. Those pods run k3s plus playpen-runner control-plane, which publishes the kubeconfig and guest API server metadata consumed by control-plane allocations.

The operator does not proxy Redfish or console traffic. Clients reach Redfish and the serial console stream on the runner through the WireGuard tunnel. The alloc response includes the runner Redfish URL, the system URL, and the OEM serial console stream URI for convenience.

API

The operator is registered as v1alpha1.playpen.unbounded-cloud.io and is meant to be reached through the Kubernetes API server, not by calling the operator Service directly. It trusts only Kubernetes front-proxy client certificates and authorizes requests with SubjectAccessReview.

Endpoint Method Purpose
/apis/playpen.unbounded-cloud.io GET API group discovery
/apis/playpen.unbounded-cloud.io/v1alpha1 GET API version discovery
/apis/playpen.unbounded-cloud.io/v1alpha1/allocs POST Allocate an idle runner pod
/apis/playpen.unbounded-cloud.io/v1alpha1/deallocs POST Deallocate by idempotency key and delete the runner pod
/healthz GET Liveness probe
/readyz GET Readiness probe

Alloc and dealloc share one RBAC action. Both handlers authorize create on allocs.playpen.unbounded-cloud.io, so granting that action grants both API operations together.

Alloc requests require an idempotency key and a valid WireGuard public key. The idempotency key can be passed in the Idempotency-Key header or, for kubectl clients without a header flag, as idempotencyKey in the JSON body:

kubectl create --raw /apis/playpen.unbounded-cloud.io/v1alpha1/allocs \
	-f - <<'EOF'
{"idempotencyKey":"smoke-test-1","wireGuardPublicKey":"<client-wireguard-public-key>"}
EOF

The same idempotency key can be retried with the same request body. Reusing the key with a different WireGuard public key returns 409 Conflict.

Dealloc uses the same idempotency key and is idempotent:

kubectl create --raw /apis/playpen.unbounded-cloud.io/v1alpha1/deallocs \
	-f - <<'EOF'
{"idempotencyKey":"smoke-test-1"}
EOF

Kubernetes Behavior

  • Runner pods are created in --runner-namespace from --runner-image.
  • --runner-amd64-count and --runner-arm64-count set the desired idle pool size for each architecture.
  • --runner-wireguard-host-port-start and --runner-wireguard-host-port-end define the cluster-wide UDP hostPort range used for runner WireGuard endpoints.
  • Runner pods are selected from --runner-namespace using --runner-label-selector for allocation and reconciliation.
  • An alloc writes pod annotations for the client key, request hash, idempotency key hash, and allocation time, then labels the pod with an allocation ID.
  • The alloc response uses the runner node's ExternalIP and the runner pod's WireGuard hostPort as the externally reachable endpoint. If the runner node has no ExternalIP, allocs fail with 503 Service Unavailable.
  • --playpen-ttl is the only playpen pod TTL enforcement point. It deletes expired allocated pods. Deallocs also delete the allocated pod. The operator replaces deleted allocated pods during runner pool reconciliation.
  • On startup, the operator ensures the operator TLS Secret exists, then injects the serving certificate into the APIService caBundle.

Run

For local development against the current Kubernetes context:

go run ./cmd/playpen-operator --listen-addr=:8443

For the in-cluster deployment, build the shared playpen image with make image-playpen-local, render manifests with make playpen-manifests, and apply the files under deploy/playpen/rendered.

Documentation

The Go Gopher

There is no documentation for this package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL