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.
| 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.
| 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.
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.
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.
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.
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.