cocoon-common

API types

apis/v1 holds the typed Go definitions for the cocoonset.cocoonstack.io/v1 API group and the CRD YAML generated from them, under apis/v1/crds/.

Import path: github.com/cocoonstack/cocoon-common/apis/v1.

Resources

Kind Short names Purpose
CocoonSet cs, cocoonsets Declarative agent cluster: one main agent, agent.replicas sub-agents, and any number of toolbox VMs
CocoonHibernation ch, cocoonhibernations Per-pod hibernate / wake request

Both carry a status subresource and a Ready condition built by k8s.NewReadyCondition.

CocoonSetSpec

Field Default Notes
suspend false Suspends the whole set
snapshotPolicy always always / main-only / never
hibernatePolicy retain retain keeps the scheduling seat while suspended; release frees it once the hibernate snapshot is registry-verified
nodePool default Selected via the cocoonstack.io/pool node label
snapshotCompatibilityClass unset Certified guest-visible CPU ABI; rendered as a hard node selector
nodeName unset Pins the set to one node (cross-node migrate); empty leaves placement to the scheduler
agent required AgentSpec — image, replicas, mode, plus the shared VMOptions
toolboxes unset []ToolboxSpec — named auxiliary VMs

VMOptions is inlined into both AgentSpec and ToolboxSpec: os, backend, connType, network, forcePull, noDirectIO, probePort, storage, resources.

Enum defaults

Every enum type is a string with a +kubebuilder:validation:Enum marker, an IsValid() predicate, and — where a zero value is meaningful — a Default() that resolves the empty string. Both sides of a contract call Default(), so an unset field means the same thing to the operator and to vk-cocoon.

Type Values Default()
AgentMode clone, run clone
ToolboxMode run, clone, static run
OSType linux, windows, android, macos linux
SnapshotPolicy always, main-only, never always
HibernatePolicy retain, release retain
Backend cloud-hypervisor, firecracker cloud-hypervisor
ConnType ssh, rdp, vnc, adb none — empty means “infer from OS”
HibernationDesire Hibernate, Wake none

CocoonSetPhase and CocoonHibernationPhase are status-only enums with no IsValid() — the controller is their only writer.

Backend: firecracker boots a kernel directly and accepts only OCI VM images; cloudimg URLs and Windows guests are rejected at admission and again at run time.

CEL rules inside the CRDs

Two rules ship in the generated CocoonSet CRD, so they hold for any client that never touches the Go types:

- message: hibernatePolicy=release requires agent.replicas=0 and no toolboxes
  rule: '!has(self.hibernatePolicy) || self.hibernatePolicy != ''release''
    || ((!has(self.agent.replicas) || self.agent.replicas == 0)
    && (!has(self.toolboxes) || size(self.toolboxes) == 0))'
- message: snapshotCompatibilityClass is immutable once set
  rule: '!has(oldSelf.snapshotCompatibilityClass)
    || (has(self.snapshotCompatibilityClass)
    && self.snapshotCompatibilityClass == oldSelf.snapshotCompatibilityClass)'

Seat release is restricted to a main-only set until sub-agent and toolbox restore intent is defined. The compatibility class is immutable because changing it would invalidate every memory snapshot the set has already published.

CocoonHibernation adds one: spec.podRef is immutable.

Regeneration

zz_generated.deepcopy.go and apis/v1/crds/*.yaml are generated by controller-gen, pinned through hack/tools.go so no separate binary download is needed:

make generate    # deepcopy methods
make manifests   # CRD YAML

Run both after any change to apis/v1/*_types.go and commit the result. The lint workflow re-runs them and fails on a dirty tree, so a forgotten regeneration is caught in CI rather than in a downstream repo.

Field godoc becomes the CRD description and is what kubectl explain prints — it is API documentation, not a code comment, and removing it changes the generated YAML.

Downstream consumption

Operators depend on the module and copy the CRD YAML into their own kustomize tree (make import-crds in cocoon-operator) rather than vendoring the manifests by hand.