# Options ## deployment\.enable Whether to enable rendering objects into named deployment units\. *Type:* boolean *Default:* ```nix false ``` *Example:* ```nix true ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.declaredUnits Every unit this configuration declares\. ` ekn ` reads it only to warn: pruning an object whose unit is not in this list is correct, and is also one line of configuration away from deleting ArgoCD and the CNI\. *Type:* list of string *(read only)* *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.deployBranch Git branch that rendered manifests are committed to, and that GitOps tooling (ArgoCD/Flux) should sync from\. One branch per easykubenix instance – an “environment” is just whichever instance you evaluate, same as one NixOS system is one environment\. *Type:* string *Example:* ```nix "production" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.engine\.pause Workloads ` ekn kubeapply --pause-engine ` scales to zero for the duration of a direct apply, and restores afterwards\. A direct apply and a running GitOps engine are two writers of the same objects, and whichever ran last wins – so a full deploy against a live engine is undone at the next sync, with nothing reporting it\. **Name the engine’s reconciler, and nothing else\.** The test is which workloads hold cluster-wide write permission, not which ones belong to the engine\. On a stock ArgoCD install (measured on nixlab2 from the ClusterRoles bound to each ServiceAccount) that is the application controller alone: the repo server holds no write bindings at all, so scaling it buys nothing and costs the controller its target state on resume\. Two things this does not stop, both worth knowing rather than working around\. ` argocd-server ` keeps cluster-wide ` delete ` and ` patch `, so a person clicking Sync in the UI during an apply still writes – scaling it too would take away the UI people want for watching\. And an ApplicationSet controller regenerates Applications; if you run one, it belongs in this list\. Each workload carries ` ekn.dev/paused-replicas ` while it is down, so an ` ekn ` that dies mid-apply leaves the count to restore on the cluster rather than in a file\. A later run finds it and can finish\. These objects are **excluded from the apply set** while paused, and protected from its prune\. They are usually in ` kubernetes.generated ` themselves, declaring ` replicas: 1 `, so applying them would wake the engine in the middle of the apply that paused it\. The cost is that this mode can never update the engine’s own reconciler; ` ekn ` says so rather than passing over it\. *Type:* list of (submodule) *Default:* ```nix [ ] ``` *Example:* ```nix [ { namespace = "argocd"; name = "argo-cd-argocd-application-controller"; kind = "StatefulSet"; } ] ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.engine\.pause\.\*\.kind What to scale\. Only these two have a replica count ` ekn ` can restore\. *Type:* one of “Deployment”, “StatefulSet” *Default:* ```nix "Deployment" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.engine\.pause\.\*\.name Workload name\. *Type:* string *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.engine\.pause\.\*\.namespace Namespace the workload lives in\. *Type:* string *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.fieldManager The server-side-apply field manager this instance writes as, for every apply that does not name another one\. **Set this rather than each unit’s ` fieldManager `\.** A whole-instance ` ekn kubeapply ` is one group with no unit, so before this option it could not name a manager at all and wrote as the built-in default\. A deployment that set ` deployment.units..fieldManager ` on every unit therefore still had two managers on its objects: the units’ one from a targeted apply, and the built-in one from a whole-instance apply\. That split is not cosmetic\. Server-side apply removes a field only when its **owning** manager stops declaring it, so a field the built-in manager wrote and the successor does not declare stays on the object for ever – the successor’s apply cannot drop what it does not own, and ` force ` does not help, because two different fields are not a conflict\. A probe that changes handler type is then refused by the API server forever: ` may not specify more than 1 handler type `\. ` ekn reclaim ` moves existing ownership onto this manager\. This option is what stops the split happening again\. ` deployment.units..fieldManager ` defaults to this and still overrides it, for a bootstrap unit whose successor differs from the instance’s\. *Type:* string *Default:* ```nix "ekn" ``` *Example:* ```nix "argocd-controller" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.handAppliedUnits The units a whole-instance ` ekn kubeapply --prune ` must not touch: every unit whose objects do not reach ` kubernetes.generated `\. ` ekn ` selects ` ekn.dev/environment=E,ekn.dev/deployment-unit notin (these) `\. Each of these units renders a whole nested instance that only ` ekn kubeapply --target ` applies, so its objects carry the environment label without ever being in a whole-instance apply’s desired set\. Without the exclusion that prune deletes them, and for a bootstrap unit that is ArgoCD and the CNI\. Computed by **inverting** the routing-only test, not by listing the nested ones\. A unit is left in scope only when it is demonstrably ` class = "kubernetes" ` with no ` modules ` of its own; anything else, including a class nobody has written yet, is excluded\. A wrong exclusion leaves an object running, a wrong inclusion deletes it, and the two mistakes are not worth the same\. ` modules ` is a list of deferred modules, so it cannot be serialised for ` ekn ` to test itself\. This option is the answer, evaluated here\. *Type:* list of string *(read only)* *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.path Subdirectory within the branch where rendered manifests are stored\. *Type:* string *Default:* ```nix "./" ``` *Example:* ```nix "./clusters/my-cluster" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.sourceBranch Git branch the exact source tree (working copy, including uncommitted edits) is snapshotted to at deploy time, paired 1:1 with ` deployBranch ` via two-parent commits – every deploy commit also points at the source commit that produced it\. Null disables this snapshot/dual-commit behavior, falling back to a plain single-branch commit\. *Type:* null or string *Default:* ```nix null ``` *Example:* ```nix "production-source" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.tofuUnits Every ` deployment.units. ` whose ` class ` is “tf”, with the OpenTofu configuration it rendered and the ` tofu ` binary that can apply it\. The parallel to ` kubernetes.deploymentUnits `, and deliberately not an entry in it\. That attrset is a published schema – ` ekn ` validates it with pydantic, and every entry must carry ` objects ` – so widening it to hold entries that have none would cost each consumer a branch and buy nothing\. Under ` deployment ` rather than ` tofu `, because ` tofu.* ` inside a “tf” instance is that instance’s own configuration\. These are a Kubernetes instance’s *view* of the units below it\. ` configFile ` and ` tofu ` are store paths, and neither is built at evaluation time – ` ekn tofu ` realises both before it runs anything\. ` dependencies ` is the transitive closure, deepest first, and ` ekn tofu ` takes that order literally: each entry is its own ` tofu ` invocation, run before this unit’s\. Every dependency of a “tf” unit is itself a “tf” unit\. An assertion refuses one that crosses classes, because ` dependencies ` means “apply this one too, as part of applying me” and the two classes are not applied by the same thing\. *Type:* anything *(read only)* *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.unitFieldManagers Each unit’s ` fieldManager `, so a **whole-instance** apply can write each object as the manager its own unit declares\. A whole-instance apply is one group and wrote everything as the instance’s default manager, even though every routed object carries the unit that names one\. That is right for an apply that runs again – it keeps conflict detection – and wrong for a full deploy standing in for a paused engine, which has a successor and does not run again\. ` ekn ` reads this **only while the engine is paused**\. Two writers sharing one manager name are one manager to the API server, so each apply’s field set replaces the other’s; using the engine’s name while the engine runs is worse than the orphaned fields it fixes\. *Type:* attribute set of string *(read only)* *Default:* ```nix { } ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units Named GitOps sync targets – pure path-routing within the single ` deployBranch `/` sourceBranch ` pair for this instance\. The target is the single source of truth for where its manifests land, and how many controllers exist (Argo, Flux, both, neither) is up to whatever object references the target, not the target itself\. A target’s objects come from either of two places, and it can use both at once: - This instance’s own objects, routed by name with ` ekn.deploymentUnit ` – rather than embedding a reference to the Application/Kustomization that happens to sync them\. - ` modules `, a whole separate easykubenix configuration evaluated just for this target\. Its objects render into the target’s ` path ` and stay out of this instance’s ` kubernetes.generated ` entirely, which is what makes it usable for bootstrapping a GitOps engine\. *Type:* attribute set of (submodule) *Default:* ```nix { } ``` *Example:* ```nix { apps.path = "clusters/home/apps"; bootstrap = { path = "bootstrap"; modules = [ ./bootstrap/argocd.nix ]; }; } ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.annotations Annotations stamped onto every object in this target, with the same semantics as ` labels ` above\. The per-object form is the useful one here: ArgoCD’s ` argocd.argoproj.io/tracking-id ` – its default ownership mechanism since 3\.0 – encodes each object’s own group/kind/namespace/name, so a constant cannot express it\. See ` ekn.lib.argocdTrackingId `\. *Type:* attribute set of (string or function that evaluates to a(n) (null or string)) *Default:* ```nix { } ``` *Example:* ```nix { "argocd.argoproj.io/tracking-id" = ekn.lib.argocdTrackingId { app = "root"; namespace = "default"; }; } ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.class What kind of configuration ` modules ` is, which decides the base modules the nested instance is evaluated with and what this unit produces\. ` kubernetes ` is a whole easykubenix configuration rendering Kubernetes objects, which is every unit that existed before this option\. ` tf ` is an OpenTofu configuration rendering ` config.tf.json ` – see ` tofu.nix ` and ` design/opentofu.md `\. It declares no Kubernetes option at all, so its objects reach neither ` kubernetes.generated ` nor ` kubernetes.deploymentUnits `, and nothing routed with ` ekn.deploymentUnit ` may name it\. The module system enforces this rather than trusting it\. The nested evaluation is given this class, and a module carrying the other one fails at the import naming both\. *Type:* one of “kubernetes”, “tf” *Default:* ```nix "kubernetes" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.dependencies Other deployment units this one needs on the cluster\. ` ekn kubeapply --target ‹name› ` contributes each of their objects to its apply plan, transitively\. Apply-time only\. ` ekn commit ` still writes each unit to its own ` path ` and nothing else: a dependency is about what has to be *on the cluster*, not about where a manifest lives\. The use it exists for is a bootstrap unit that needs credentials it cannot render\. Put the Secrets in their own unit, depend on it, and re-seeding them is ` ekn kubeapply --target ` on its own – rather than a full bootstrap apply, which is the thing you do only after breaking a cluster badly enough that ArgoCD or the CNI is gone\. Not an ordering constraint\. Objects from every contributing unit go into one apply, and ` ekn.resourcePriority ` orders that apply by kind as always\. Each unit keeps its own prune scope, because ` ekn.dev/deployment-unit ` is rendered per unit\. Naming a dependency does not widen what this unit’s ` --prune ` deletes\. A cycle is an error, and so is a name no ` deployment.units ` entry declares\. *Type:* list of string *Default:* ```nix [ ] ``` *Example:* ```nix [ "bootstrap-secrets" ] ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.fieldManager Server-side-apply field manager ` ekn kubeapply --target ‹name› ` writes as\. Apply-time only – it never appears in the rendered manifests, because it is a property of who applied an object rather than of the object\. Set it to the name of the controller that takes the objects over afterwards, which for a bootstrap target is the point of the whole exercise\. Two managers declaring the same field is an SSA conflict, forcing ` Force=true ` on the successor’s side, and worse: SSA only drops a field when its owning manager stops declaring it, so every field ` ekn ` set and the successor does not stays owned by ` ekn ` forever, because a bootstrap apply never runs again\. Applying as the successor makes the handover complete instead – fields the bootstrap set and steady state does not are simply removed\. The cost is that a *second* apply of this target silently overwrites the successor’s fields instead of reporting a conflict, since they are now the same manager\. That is the trade, and it is acceptable only because a bootstrap target runs once by definition\. *Type:* string *Default:* ```nix config.deployment.fieldManager ``` *Example:* ```nix "argocd-controller" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.labels Labels stamped onto every object in this target – both the ones routed here with ` ekn.deploymentUnit ` and the ones ` modules ` renders\. Baked into the rendered manifests, so the committed YAML and what ` ekn kubeapply --target ‹name› ` applies agree\. One entry is here by default: ` ekn.dev/deployment-unit `, holding this unit’s name\. It is what makes ` kubectl get all -A -l ekn.dev/deployment-unit=‹name› ` answer, and it is what scopes pruning\. ` mkForce ` a different string if the name does not suit\. Do not remove it and do not make it a function: an assertion rejects both, because a unit that cannot be selected by this label cannot be pruned, and its objects look unowned to the next whole-instance prune\. A value may be a function of the object rather than a string, for metadata that has to encode the object’s own identity – ` ekn.lib.argocdTrackingId ` is one\. Such a function may return ` null ` to leave that one object alone, which is not a nicety: ArgoCD deliberately puts no tracking annotation on a CRD, so stamping one anyway would make every CRD permanently OutOfSync\. These win over labels the object already carries\. That is deliberate and it matters: Helm charts routinely set ` app.kubernetes.io/instance ` to their release name, which is exactly the key a GitOps engine may be using to decide ownership\. An object routed here also appears in ` kubernetes.generated `, and carries the same stamp there\. Both copies must agree: a whole-instance apply and a ` --target ` apply write as the same field manager, so a stamp on only one of them flips with whichever apply ran last\. See ` stampRouted ` in kubernetes\.nix\. *Type:* attribute set of (string or function that evaluates to a(n) (null or string)) *Default:* ```nix { } ``` *Example:* ```nix { "app.kubernetes.io/instance" = "root"; } ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.modules Modules making up a whole separate easykubenix configuration, rendered into this target’s ` path ` and nowhere else\. Its objects never reach this instance’s ` kubernetes.generated `, so a plain ` ekn kubeapply ` (or ` ekn validate `) does not see them – only ` ekn kubeapply --target ‹name› ` does\. That separation is the point: this is for the objects a GitOps engine cannot sync because they are what makes it able to sync anything – the engine itself, its credentials, its root Application\. They get applied once, by hand, and then have a different lifecycle from everything else\. The nested instance is a complete easykubenix configuration, not a cut-down one, so it can render a Helm chart like any other\. It receives its parent’s evaluated config as the ` parent ` module argument, and its ` ekn.environment ` defaults to this instance’s\. Definitions concatenate, so several modules can each add to one target’s list\. *Type:* list of module *Default:* ```nix [ ] ``` *Example:* ```nix [ ./bootstrap/argocd.nix ] ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## deployment\.units\.\\.path Subdirectory within deployBranch/sourceBranch where this target’s manifests are stored\. *Type:* string *Default:* ```nix "./" ``` *Declared by:* - [easykubenix/gitops\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/gitops.nix) ## ekn\.assertCached Substituters to ask, **before applying anything**, whether they can serve every store path this apply names\. A path on none of them refuses the apply\. **Defaults to ` ekn.cacheTo `**, the destinations this same run has just pushed to\. So the check asks whether the push arrived, and no second list exists to drift from the first\. ` cacheTo = null ` leaves this empty and turns the check off, which is right for an instance with no CSI-backed store: there is nothing to assert and it should not pay for the check\. **The list has to be the caches the nodes carry**, not the ones the deploying machine happens to have configured – those are usually more, and a path only the deployer can fetch passes a check and then fails to mount\. ` cacheTo ` is already that list, curated by whoever knows where the paths are consumed, so this follows it rather than asking for the same knowledge twice\. Set this option directly where the two differ\. **What it is for\.** A CSI-mounted store path can only be substituted – a node cannot build it, because the volume names an output path\. So a path on no substituter is a mount that fails on a node, minutes later and well away from the apply that caused it\. Asserting first turns that into a refusal with the path named\. ` ekn ` never consults the local store, only these substituters, so a path this machine happens to have built does not pass\. ` ekn ` walks the whole closure rather than the named paths, which is the shape that actually bites – a present top path whose closure member is absent\. A path is *missing* when every substituter said so, and the check is *broken* when one could not answer at all\. ` ekn ` refuses either way and says which, because a cache that is down and a path that was never pushed need different fixes\. Any store URI works – ` https `, ` ssh-ng `, ` s3 `, ` file ` – because the query goes through nanopynix rather than a scheme-specific fetcher\. See issue \#37\. **The default answers “did the push arrive”, and that is a weaker question than “can a cold node get this”\.** A destination that is itself a workload in the cluster – pynixd on nixlab2 – serves a path exactly as long as that workload runs\. The check unions its substituters, so one of them holding the path is enough to pass, and a path held only by pynixd passes while pynixd is up\. Drop that destination from this list to ask the harder question\. A list of only the caches that do not depend on the cluster reports a pynixd-only path as missing, which is the outage this guard exists for rather than a false positive\. This is the guard, not the fix\. It does not push anything; see ` ekn.cacheTo `\. *Type:* list of string *Default:* ```nix [ ] ``` *Example:* ```nix [ "https://nixkube.cachix.org" ] ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.cacheAcceptNewHostKeys Accept the host key of an ` ssh:// `/` ssh-ng:// ` destination in ` ekn.cacheTo ` the first time ` ekn ` meets it, instead of failing the push\. ` ekn ` does this by adding ` -o StrictHostKeyChecking=accept-new ` to ` NIX_SSHOPTS `, which is what Nix passes to OpenSSH\. **A key that changed is still refused\.** ` accept-new ` trusts a host the first time only, so this gives up first-contact trust and keeps the protection that matters for a host you already deploy to\. The default is ` true ` because the alternative is not a safer deploy\. ` ekn deploy ` cannot prompt, so an unknown key stops the deploy with an error that names the connection and not the key, and the operator answers it by running ` ssh -o StrictHostKeyChecking=accept-new nix@host ` by hand – the same decision, made under time pressure and with less information\. Issue \#18\. Set this to ` false ` where the host keys are distributed ahead of time, for example by NixOS ` programs.ssh.knownHosts `\. A push to an unknown host then fails, and ` ekn ` names the host key as the cause\. Your own ` NIX_SSHOPTS ` wins: ` ekn ` adds nothing when that variable already sets ` StrictHostKeyChecking `\. *Type:* boolean *Default:* ```nix true ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.cacheTimeoutSec Seconds ` ekn deploy ` gives the push to ` ekn.cacheTo ` before it gives up\. ` null ` waits forever\. There is a default because forever is what it used to do\. ssh has no connect timeout of its own here, so a host that drops packets rather than refusing them leaves the push in ` SYN-SENT ` until the kernel exhausts its SYN retries, with no output the whole time – which reads as a slow validate or a hung process rather than as a cache nobody can reach\. Issue \#20 has the measurement\. ` --cache-allow-failure ` does not help with that on its own: it decides what to do once the push returns, and the point here is that it does not return\. The two work together – this bounds the wait, and that flag decides whether the deploy continues afterwards\. This bounds the whole push, not the connect, because that is the part a store URI gives us any control over\. So it has to be larger than a real push of the manifest’s store paths over the slowest link you deploy across, and the default is generous for that reason rather than tuned\. *Type:* null or (positive integer, meaning >0) *Default:* ```nix 600 ``` *Example:* ```nix 120 ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.cacheTo Destination Nix store URI (e\.g\. “ssh-ng://user@host:2222”), or a list of them, that ` ekn deploy ` and ` ekn kubeapply ` push to before they act\. ` null ` disables the cache push entirely\. **This is the only knob\.** What gets pushed is not a choice: it is every store path the rendered manifest names, found in the manifest’s *text*\. That is the same set ` ekn.assertCached ` asks about, so the push and the assertion cannot disagree about what an apply names\. The text, and not a closure, because Nix string context is what a module can take away\. nixkube’s ` discardStringContext ` strips it from every resource annotated ` nixkube/discard `\. Measured on nixkube’s own instance: store paths named as text in manifest\.json 4 paths in its closure 1 (itself) The four are the node and pynixd environments – exactly the paths a node needs to boot\. A stripped path is also not realised on the deploying machine, and ` ekn ` refuses the push rather than moving a smaller set\. Set ` nixkube.discardStringContext = false ` to keep the context that realises them\. The destination substitutes what it can reach itself, so a path both ends can fetch from a public cache never crosses this link\. **A list is allowed because one destination cannot always be enough\.** A store path is only useful where whatever mounts it can reach it, and a single destination cannot serve a path whose *consumer is that destination*\. On nixlab2 ` cacheTo ` is pynixd, and pynixd’s own environment is mounted over CSI on a node – so pushing that leg here can never bootstrap it, and it needs a substituter that does not depend on pynixd\. Every destination is pushed to, in order\. A failure in any of them fails the push, subject to ` --cache-allow-failure `: a path that reached only some of the stores that need it is the case this option exists to avoid\. A plain string stays valid and means what it always did\. This option does not decide *which* destinations an instance needs – that is a property of where its paths are consumed\. *Type:* null or string or list of string *Default:* ```nix null ``` *Example:* ```nix "ssh-ng://nix@cache.example.com:2222" ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.clusterUid The cluster this configuration is allowed to reach: the ` uid ` of the ` kube-system ` Namespace\. ` ekn kubeapply `, ` ekn reclaim `, ` ekn clusterdiff ` and ` ekn secrets ` refuse to act against any other\. **The ambient kubeconfig is not a neutral default\.** It is usually a valid, reachable, credentialed cluster that happens to be the wrong one, and there is no error to notice: the apply succeeds until something unrelated collides\. This option is what removes the default rather than guarding it\. Kubernetes has no cluster ID resource\. ` kube-system ` is created once at bootstrap and never re-created, its ` uid ` is server-generated and never reused, and reading it needs no permission an apply does not already have\. Left ` null `, every one of those commands refuses and prints the line to paste here\. Passing ` --i-dont-know-which-cluster-this-is ` runs anyway; it is deliberately hard to type and reads badly in a reviewed file, which is the point\. **A rebuilt cluster is a different cluster\.** It gets a new ` uid ` and this value has to change with it\. That is the correct answer, not an inconvenience: nothing else would have told you\. *Type:* null or string matching the pattern ^\[0-9a-f]{8}-\[0-9a-f]{4}-\[0-9a-f]{4}-\[0-9a-f]{4}-\[0-9a-f]{12}$ *Default:* ```nix null ``` *Example:* ```nix "3b2a1f0e-9d8c-4b7a-8e6f-5d4c3b2a1f0e" ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.environment Value of the ` ekn.dev/environment ` label stamped on every object ` ekn ` applies, and half of the selector it lists objects back by when pruning\. The other half is ` ekn.dev/deployment-unit `, which every deployment unit renders onto its own objects\. Together they give two prune scopes: - ` ekn kubeapply --prune ` deletes objects carrying this environment and *no* unit label, which the current apply did not produce\. - ` ekn kubeapply --target --prune ` deletes objects carrying this environment and that unit’s label, which the current apply did not produce\. The environment label is stamped by ` ekn ` at apply time rather than rendered\. That is what confines pruning to objects ` ekn ` itself applied: an object a GitOps engine synced from the committed YAML never carries it, so ` ekn ` and that engine cannot end up deleting each other’s work\. Required, with no default, and that is deliberate\. A default is a value every project shares until somebody thinks to change it\. Two easykubenix projects that both took it and both deploy to one cluster do not conflict quietly: each apply prunes the other’s objects, because from where it stands they are objects carrying its own label that its own apply did not produce\. The scope is per kind, not the whole cluster, but a kind both projects use is the normal case\. Nothing can detect that from inside one project, so the name has to be a decision somebody made\. Only a deploy needs it: rendering a manifest never reads this, so a configuration that only builds ` manifestJSONFile ` does not have to answer\. **Changing the value of a project that already deployed is not free\.** Live objects carry the label they were applied with, and ` --prune ` finds objects by that label alone\. Pick a different word and the next prune no longer recognises anything the previous one would have: those objects are not deleted, they are orphaned, and nothing reports it\. *Type:* string *Example:* ```nix "acme-production" ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.preApplyCommand Program ` ekn kubeapply ` runs before it touches the cluster, and before the ` ekn.cacheTo ` push\. A non-zero exit aborts the apply\. **It runs before the push on purpose\.** The case it exists for is a path the push cannot place: a store the cluster reads but this machine cannot write through ` ekn.cacheTo `, or a cache that has to hold a path before the workload serving ` ekn.cacheTo ` restarts\. A hook that ran afterwards could not repair what the push depends on\. ` ekn ` passes the JSON manifest of the objects this apply will send as the first argument, and in ` EKN_MANIFEST `\. It is the objects themselves, so a ` --target ` slice is the slice and a seeded Secret carries its resolved value\. ` EKN_ENVIRONMENT ` holds ` ekn.environment `, and ` EKN_TARGET ` the ` --target ` names joined by commas, or the empty string for a whole-instance apply\. **A non-zero exit always aborts, and there is no flag to soften that\.** The hook decides what it tolerates; ` ekn ` tells it what the deploy tolerates and lets the script logic deal with it: EKN_CACHE_PUSH 1 unless ` --no-cache-push ` EKN_CACHE_ALLOW_FAILURE 1 with ` --cache-allow-failure ` Both are ` 1 ` or ` 0 `, so ` [ "$EKN_CACHE_ALLOW_FAILURE" = 1 ] ` needs no case handling\. A hook that wants to be advisory reads them and exits 0 itself\. Every store path the apply names is in that manifest as text, so a hook that has to seed a cache can read them out of it rather than being told them: grep -o ‘/nix/store/\[a-z0-9]{32}-\[^"]\*’ “$1” | sort -u ` types.path `, and Nix string context is kept, so ` ekn ` builds the program before it runs it\. ` ekn ` then executes that path directly\. **Wrap a package in ` lib.getExe `\.** ` pkgs.writeScriptBin ` and its relatives build a *directory* with the script under ` bin/ `, and ` ekn ` executes the path it is given\. This is the pre half of issue \#5\. ` kluctl.preDeployScript ` is the same hook in the namespace it predates\. *Type:* null or absolute path *Default:* ```nix null ``` *Example:* ```nix lib.getExe ( pkgs.writeScriptBin "seed-the-cache" '' #!${pkgs.runtimeShell} set -euo pipefail grep -o '/nix/store/[a-z0-9]\{32\}-[^"]*' "$1" | sort -u \ | ${pkgs.cachix}/bin/cachix push nixkube '' ) ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## ekn\.resourcePriority Apply order by object kind, lowest number first\. Objects sharing a number apply together as one barrier, which is fully applied (and, for CustomResourceDefinitions, waited on to become Established) before the next barrier starts\. Defaults to Helm’s ` InstallOrder `, numbered in steps of ten so kinds can be slotted between two neighbours without renumbering the rest\. A kind absent from this set applies at 1000, which is every custom resource\. That gives four bands to number against: - ` 10 `-` 380 ` Helm’s order as-is - ` 381 `-` 999 ` late, but still before custom resources - ` 1000 ` custom resources and anything else unlisted - ` 1001 `+ after custom resources ` APIService ` and the two admission webhook configurations sit in that last band, which is the one place this deviates from Helm\. Helm sorts unknown kinds after its whole list, leaving all three ahead of every custom resource they intercept; during a bootstrap their backing workload was applied seconds earlier and is not serving yet, so each intercepted request costs a full timeout or fails discovery outright\. The four in-apiserver admission kinds deviate the other way: ` ValidatingAdmissionPolicy `, ` MutatingAdmissionPolicy ` and their bindings sit right after ` CustomResourceDefinition `\. They need no backend, so they apply before every object they admit, and a pod of the same apply is mutated and validated like any later one\. Definitions merge per key, so setting one kind keeps the defaults for every other\. Replacing the set wholesale takes ` lib.mkForce `\. *Type:* attribute set of signed integer *Default:* ```nix { APIService = 1010; ClusterRole = 160; ClusterRoleBinding = 180; ClusterRoleBindingList = 190; ClusterRoleList = 170; ConfigMap = 110; CronJob = 330; CustomResourceDefinition = 150; DaemonSet = 250; Deployment = 290; HorizontalPodAutoscaler = 300; Ingress = 350; IngressClass = 340; Job = 320; LimitRange = 50; MutatingAdmissionPolicy = 152; MutatingAdmissionPolicyBinding = 154; MutatingWebhookConfiguration = 1020; Namespace = 20; NetworkPolicy = 30; PersistentVolume = 130; PersistentVolumeClaim = 140; Pod = 260; PodDisruptionBudget = 70; PodSecurityPolicy = 60; PriorityClass = 10; ReplicaSet = 280; ReplicationController = 270; ResourceQuota = 40; Role = 200; RoleBinding = 220; RoleBindingList = 230; RoleList = 210; Secret = 90; SecretList = 100; Service = 240; ServiceAccount = 80; StatefulSet = 310; StorageClass = 120; ValidatingAdmissionPolicy = 152; ValidatingAdmissionPolicyBinding = 154; ValidatingWebhookConfiguration = 1030; } ``` *Declared by:* - [easykubenix/ekn\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/ekn.nix) ## helm\.package The kubernetes-helm package to use\. *Type:* package *Default:* ```nix pkgs.kubernetes-helm ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases Attribute set of helm releases\. A thin wrapper over ` ekn.lib.importHelm `, which is the primitive and takes the same arguments\. Use the function directly when building objects from a plain function rather than from a module – it returns a config fragment you place with ` lib.mkMerge `, with no option to declare and read back\. *Type:* attribute set of (submodule) *Default:* ```nix { } ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.apiVersions API versions to tell Helm the target cluster has (` --api-versions `), for a chart that gates templates on ` .Capabilities.APIVersions.Has `\. ` helm template ` normally fills that list from the live cluster\. Rendering here runs against no cluster, so the list is empty and every such check answers “absent” – however many CRDs the real cluster has\. The quiet failure is the one to watch for\. A chart that calls ` fail ` stops the render with a readable message (cilium does this)\. A chart that wraps the template in ` if .Capabilities.APIVersions.Has ` instead emits nothing: the render succeeds, the apply succeeds, every Application reports Healthy, and the object is simply absent\. Measured on a real cluster: ArgoCD gates all seven of its ServiceMonitor templates this way and offers no override value, so the component deploying everything else was the one thing nothing scraped\. Six further charts that same repository pins carry the same gate – argo-workflows, oauth2-proxy, reloader, openebs, aws-ebs-csi – so it is a class rather than one chart’s quirk, and the right place to set this is wherever every chart is rendered rather than on each one that bites\. Nothing downstream can catch it\. A render missing a gated object and a render that correctly had none are byte-identical – there is no artefact to compare, no object to be absent from a diff, nothing for validation to reject\. That is why it has to be answered here, where the question is asked\. The chart is not wrong: its ` if ` exists so it does not emit a ServiceMonitor into a cluster that would reject one\. It answered accurately about the cluster ` helm template ` was pointed at, which was no cluster\. Helm matches these strings literally, and charts disagree on which spelling they test – ArgoCD asks for ` monitoring.coreos.com/v1 `, external-secrets for ` monitoring.coreos.com/v1/ServiceMonitor `\. One form leaves the other chart rendering nothing, so pass both\. *Type:* list of string *Default:* ```nix [ ] ``` *Example:* ```nix [ "monitoring.coreos.com/v1" "monitoring.coreos.com/v1/ServiceMonitor" ] ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.chart Helm chart to use *Type:* package or absolute path *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.crdSplit Route CustomResourceDefinitions to ` kubernetes.crds ` instead of ` kubernetes.resources `\. See ` ekn.lib.importYaml ` for the measured cost of turning it off, and for the pipeline stages a split CRD skips\. *Type:* boolean *Default:* ```nix true ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.includeCRDs Whether to include CRDs\. Warning: Always including CRDs here is dangerous and can break CRs in your cluster as CRDs may be updated unintentionally\. An interactive ` helm install ` NEVER updates CRDs, only installs them when they are not existing\. See https://github\.com/helm/community/blob/aa8e13054d91ee69857b13149a9652be09133a61/hips/hip-0011\.md Only set this to true if you know what you are doing and are manually checking the included CRDs for breaking changes whenever updating the Helm chart\. *Type:* boolean *Default:* ```nix false ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.kubeVersion Kubernetes version to build chart for *Type:* string *Default:* ```nix "1.37.1" ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.name Helm release name *Type:* string *Default:* ```nix "‹name›" ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.namespace Namespace to install the helm chart to\. This is ` .Release.Namespace ` and ` --namespace `, and it also creates the Namespace object\. It does NOT put a namespace on an object whose template omits one – see ` ekn.lib.importHelm `\. *Type:* null or string *Default:* ```nix null ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.noHooks Wether to include Helm hooks\. Without this all hooks run immediately on apply since we are bypassing the Helm CLI\. However, some charts only have minor validation hooks (e\.g\., upgrade version skew validation) and are safe to ignore\. *Type:* boolean *Default:* ```nix false ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.transformers Functions from this release’s whole object list to a new one, applied in order\. Passed straight through to ` ekn.lib.importHelm ` and on to ` ekn.lib.importYaml `, where the semantics are documented – they run before the CRD split and before the objects are grouped by namespace, they see CRDs, and a marker is safe in one\. This replaced a per-object ` overrides ` option\. ` map f ` expresses that, so the two hooks bought nothing but an ordering rule to remember\. *Type:* list of function that evaluates to a(n) list of (attribute set) *Default:* ```nix [ ] ``` *Example:* ```nix [ (objects: map (object: object // { metadata = object.metadata // { namespace = "app"; }; }) objects) ] ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## helm\.releases\.\\.values Values to pass to chart *Type:* Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support) *Default:* ```nix { } ``` *Declared by:* - [easykubenix/helm\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/helm.nix) ## importyaml Kubernetes manifests imported from YAML\. A thin wrapper over ` ekn.lib.importYaml `, which is the primitive and takes the same arguments\. Use the function directly when building objects from a plain function rather than from a module – it returns a config fragment you place with ` lib.mkMerge `, with no option to declare and read back\. *Type:* attribute set of (submodule) *Default:* ```nix { } ``` *Declared by:* - [easykubenix/importyaml\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/importyaml.nix) ## importyaml\.\\.crdSplit Route CustomResourceDefinitions to ` kubernetes.crds ` instead of ` kubernetes.resources `\. See ` ekn.lib.importYaml ` for the measured cost of turning it off, and for the pipeline stages a split CRD skips\. *Type:* boolean *Default:* ```nix true ``` *Declared by:* - [easykubenix/importyaml\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/importyaml.nix) ## importyaml\.\\.src Should be either a derivation or URL for builtins\.fetchTree *Type:* package or string *Declared by:* - [easykubenix/importyaml\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/importyaml.nix) ## importyaml\.\\.transformers Functions from this source’s whole object list to a new one, applied in order\. Passed straight through to ` ekn.lib.importYaml `, where the semantics are documented – they run before the CRD split and before the objects are grouped by namespace, they see CRDs, and a marker is safe in one\. This replaced a per-object ` overrides ` option\. ` map f ` expresses that, so the two hooks bought nothing but an ordering rule to remember\. *Type:* list of function that evaluates to a(n) list of (attribute set) *Default:* ```nix [ ] ``` *Example:* ```nix [ (objects: map (object: object // { metadata = object.metadata // { namespace = "app"; }; }) objects) ] ``` *Declared by:* - [easykubenix/importyaml\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/importyaml.nix) ## kluctl\.package The kluctl package to use\. *Type:* package *Default:* ```nix pkgs.kluctl ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kluctl\.deployment Anything to be rendered into deployment\.yaml *Type:* Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support) *Default:* ```nix { } ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kluctl\.excludeDeploymentUnits Names of ` deployment.units ` whose objects kluctl should not deploy\. Use this once a target has its own deployment path (e\.g\. a one-time bootstrap apply plus the GitOps controller syncing itself from there) to avoid kluctl and that controller fighting over the same objects\. Objects routed to a target *not* listed here still deploy via kluctl as normal, so a GitOps migration can move one target at a time instead of all-or-nothing\. *Type:* list of string *Default:* ```nix [ ] ``` *Example:* ```nix [ "bootstrap" ] ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kluctl\.files Attribute set where name is filename and value is string to be put into the file *Type:* attribute set of string *Default:* ```nix { } ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kluctl\.postDeployScript Bash script that runs just after deploying *Type:* strings concatenated with “\\n” *Default:* ```nix "" ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kluctl\.preDeployScript Bash script that runs just before deploying, useful to push manifests to a binary cache\. JSON manifest file is passed as first argument *Type:* strings concatenated with “\\n” *Default:* ```nix "" ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kluctl\.project Anything to be rendered into \.kluctl\.yaml *Type:* Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support) *Default:* ```nix { targets = [ { name = "local"; } ]; } ``` *Declared by:* - [easykubenix/kluctl\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kluctl.nix) ## kubernetes\.package The kubernetes package to use\. *Type:* package *Default:* ```nix pkgs.kubernetes ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.apiMappingFile A JSON file to extend apiMappings\. Generated by calling ` kubectl api-resources --output=json > mappings.json ` *Type:* absolute path *Default:* ```nix /home/runner/work/easykubenix/easykubenix/easykubenix/apiResources/v1.33.json ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.apiMappings Map of kind to apiVersion\. Merged with mappings from ` apiMappingFile `\. *Type:* attribute set of string *Default:* ```nix { } ``` *Example:* ```nix { Cluster = "cluster.x-k8s.io/v1beta1"; HCloudMachineTemplate = "infrastructure.cluster.x-k8s.io/v1beta1"; HCloudRemediationTemplate = "infrastructure.cluster.x-k8s.io/v1beta1"; HelmChartProxy = "addons.cluster.x-k8s.io/v1alpha1"; HelmReleaseProxy = "addons.cluster.x-k8s.io/v1alpha1"; HetznerCluster = "infrastructure.cluster.x-k8s.io/v1beta1"; KubeadmConfigTemplate = "bootstrap.cluster.x-k8s.io/v1beta1"; KubeadmControlPlane = "controlplane.cluster.x-k8s.io/v1beta1"; MachineDeployment = "cluster.x-k8s.io/v1beta1"; MachineHealthCheck = "cluster.x-k8s.io/v1beta1"; } ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.clusterInfo\.ipFamilies IP families the cluster’s service CIDR serves – what a Service’s ` spec.ipFamilies ` and ` spec.ipFamilyPolicy ` must fit for admission (the API server’s ` --service-cluster-ip-range `)\. One entry is a single-stack cluster, both is DualStack\. A Service the stack cannot serve is denied outright at admission; declaring the real stack here moves that denial to evaluation time with the Service named, and picks ` validation.serviceSubnet ` to match\. The default is the single-stack IPv4 cluster that ` 10.96.0.0/16 ` serves\. *Type:* non-empty (list of (one of “IPv4”, “IPv6”)) *Default:* ```nix [ "IPv4" ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.clusterInfo\.serviceCidr\.ipv4 The cluster’s IPv4 service CIDR\. The default is the range the single-stack IPv4 default of ` ipFamilies ` describes\. Set it to ` null ` only together with dropping ` IPv4 ` from ` ipFamilies `\. *Type:* null or string matching the pattern (\[0-9]{1,3}\\\.){3}\[0-9]{1,3}/\[0-9]{1,2} *Default:* ```nix "10.96.0.0/16" ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.clusterInfo\.serviceCidr\.ipv6 The cluster’s IPv6 service CIDR; ` null ` – the default – on an IPv4-only cluster\. Set it together with adding ` IPv6 ` to ` ipFamilies `\. *Type:* null or string *Default:* ```nix null ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.coerceLabelsAndAnnotations Kubernetes ` labels `/` annotations ` are strictly ` map[string]string ` – every value must be a string, anywhere a ` labels ` or ` annotations ` attrset appears (not just top-level ` metadata `: pod templates, job templates, PVC templates etc\. each carry their own)\. When enabled (the default), Nix ` bool ` values are converted via ` lib.boolToString ` and ` int ` values via ` builtins.toString ` automatically\. Values are always verified to be strings regardless of this setting – disabling it only turns bools/ints from “auto-fixed” into “hard error at eval time”, it never disables the check itself\. *Type:* boolean *Default:* ```nix true ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.crds Pre-rendered, already-complete Kubernetes objects (typically CustomResourceDefinitions from Nix-rendered Helm charts) that bypass ` kubernetes.objects `’ per-object submodule and its expensive ekn\.lib\.kubeValueType value-checking entirely\. Still passes through ` ekn.deploymentUnit ` GitOps routing and the final YAML render, just skips generators/transformers/filters and the auto-defaulting ` kubernetes.objects ` provides\. *Type:* list of (attribute set) *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.deploymentUnits Objects grouped by the ` deployment.units. ` they route to (via ` ekn.deploymentUnit `), each group paired with that target’s resolved ` {path} `\. Objects with no ` ekn.deploymentUnit ` set are omitted\. The branch(es) these all land on come from the instance-wide ` deployment.deployBranch `/` deployment.sourceBranch `, not from the target\. This is derived before the ` ekn ` field is stripped from rendered Kubernetes objects\. Each entry also carries ` dependencies `: every unit that one needs on the cluster, transitively, itself excluded\. See ` deployment.units..dependencies `\. *Type:* anything *(read only)* *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.filters List of functions that filter objects *Type:* list of function that evaluates to a(n) boolean *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.generated The final, generated Kubernetes list objects *Type:* anything *(read only)* *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.generatedByPath The final, generated Kubernetes objects by attrPath *Type:* anything *(read only)* *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.generatedExportable ` generated `, minus every object holding an ` ekn.envSeed ` reference\. The two lists differ by who applies them, not by what they contain: - ` generated ` is for ` ekn `, which resolves a seed reference at apply time by substituting the environment variable it names\. - ` generatedExportable ` is for anything that hands objects to a different applier – a GitOps target that ArgoCD then syncs, ` kluctl `, or a manifest a person feeds to ` kubectl apply `\. A seeded object must not reach the second kind\. Nothing else can resolve the reference, so it would apply ` $ekn:env:VARNAME ` as the literal value and overwrite a live credential with it\. ` ekn validate ` deliberately stays on ` generated `: a reference is a plain string, so the manifest is schema-valid and the schema check has nothing to object to\. *Type:* anything *(read only)* *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.generatedWithEkn Like ` generated `, but with each object’s ` ekn ` routing metadata still attached (` generated ` strips it)\. Consumed by anything that needs to see EKN metadata alongside the rendered object, e\.g\. ` deploymentUnits `\. *Type:* anything *(read only)* *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.generators List of functions that generate object attrsets *Type:* list of function that evaluates to a(n) (attribute set) *Default:* ```nix [ ] ``` *Example:* ```nix '' kubernetes.generators = [ ( object: lib.optionalAttrs ( (lib.elem (object.kind or "") [ "Deployment" "StatefulSet" "DaemonSet" ]) && object.metadata.annotations.genvpa or "true" == "true" && !lib.hasAttrByPath [ object.metadata.namespace "VerticalPodAutoscaler" object.metadata.name ] config.kubernetes.objects ) { apiVersion = "autoscaling.k8s.io/v1"; kind = "VerticalPodAutoscaler"; metadata = { inherit (object.metadata) name namespace; }; spec = { targetRef = { inherit (object) apiVersion kind; inherit (object.metadata) name; }; updatePolicy.updateMode = "InPlaceOrRecreate"; }; } ) ]; '' ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.novalidateKeys ` {kind, namespace, name} ` triples for every object with ` ekn.novalidate = true ` – deliberately just the identifying keys, not the full objects (which ` generated `/` manifestJSONFile ` already provide), so ` ekn validate ` can force_json this cheaply without re-forcing the entire generated set a second time\. Used by ` Validate.run() ` to skip applying objects that can never be meaningfully verified in its throwaway etcd+apiserver harness (e\.g\. an aggregated APIService with no real backing Service running)\. *Type:* anything *(read only)* *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.objectChecks Functions from a rendered object to ` { errors ? [ ]; warnings ? [ ]; } `, lists of messages\. An error throws and a warning prints when an output forces the object\. Use this instead of ` assertions ` for a check of one object\. An assertion walks every object for any output, so ` ekn kubeapply --target ` would pay for the whole instance\. A check here costs only the objects an output holds\. Not a ` transformers ` entry: any transformer turns on the deep marker pass over every object, and transformers skip ` kubernetes.crds `\. *Type:* list of function that evaluates to a(n) (attribute set) *Default:* ```nix [ ] ``` *Example:* ```nix [ (object: { errors = lib.optional (object.kind == "Pod") "${object.metadata.name}: use a Deployment, not a bare Pod"; }) ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.objects Kubernetes objects, grouped by namespace, then kind\. apiVersion is automatically injected (if apiMappings for the object exists) kind is automatically injected metadata\.name is automatically injected metadata\.namespace is automatically injected if namespace isn’t “none” *Type:* attribute set of open submodule of attribute set of open submodule of attribute set of open submodule of (Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support)) with mkIfExists support with mkIfExists support with mkIfExists support *Default:* ```nix { } ``` *Example:* ```nix { kubernetes = { objects = { easykubenix = { ConfigMap = { myconfig = { data = { key = "value"; }; }; }; }; none = { Namespace = { easykubenix = { }; }; }; }; }; } ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.objects\.\\.\\.\\.apiVersion The object’s apiVersion\. Evaluation fails when it is not set and the kind has no ` kubernetes.apiMappings ` entry\. *Type:* string *Default:* the ` kubernetes.apiMappings ` entry of the object’s kind ## kubernetes\.objects\.\\.\\.\\.ekn EKN-only metadata for this Kubernetes object\. *Type:* submodule *Default:* ```nix { } ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.after Objects that must exist before ` ekn kubeapply --converge ` creates this one\. Rendered as the ` kappy.dev/after ` annotation; the converging apply holds the object, without sending it, until each exists, for up to ` --wait-seconds `\. For what the API server accepts and a controller then abandons: a CloudNativePG Cluster created before its managed role’s password Secret records the role as unreconcilable and never retries it\. A dependency may be something no render contains, such as a Secret a controller writes\. Creation only: an object that already exists is applied whatever its dependencies are doing\. The barrier apply and the validation harness ignore it\. *Type:* list of (submodule) *Default:* ```nix [ ] ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.after\.\*\.apiVersion The apiVersion of the object to wait for\. *Type:* string ## kubernetes\.objects\.\\.\\.\\.ekn\.after\.\*\.kind The kind of the object to wait for\. *Type:* string ## kubernetes\.objects\.\\.\\.\\.ekn\.after\.\*\.name The name of the object to wait for\. *Type:* string ## kubernetes\.objects\.\\.\\.\\.ekn\.after\.\*\.namespace Null for a cluster-scoped object\. *Type:* null or string *Default:* ```nix null ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.deploymentUnit Name of the ` deployment.units. ` this object routes to\. Deliberately single-valued, not a list: an object synced by two GitOps targets at once means two controllers independently reconciling (and potentially pruning) the same resource\. The field itself is EKN-only and is stripped before Kubernetes manifests are rendered\. Its *value* is not: the object’s copy in ` kubernetes.deploymentUnits ` carries it in the ` ekn.dev/deployment-unit ` label, so the unit an object belongs to survives to the cluster whatever applies it\. The copy in ` kubernetes.generated ` is unstamped, as it is for every other per-unit label\. *Type:* null or string *Default:* ```nix null ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.novalidate Skip this object in ` ekn validate `’s ephemeral etcd+kube-apiserver harness\. For objects that can never be meaningfully verified there regardless of manifest correctness – e\.g\. an aggregated APIService, whose backing Service/Pod never actually runs in a throwaway, single-shot apiserver with no controllers or kubelets, so the apiserver 500s/503s on it (or on discovery calls that touch it) no matter what\. Applied for real via ` ekn kubeapply `/GitOps as normal; this only affects the validation harness\. *Type:* boolean *Default:* ```nix false ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.probe How ` ekn kubeapply ` sees that this object is in effect: a server dry-run and the answer it must give\. Exactly one of ` matches ` and ` denied `\. Rendered as the ` kappy.dev/probe ` annotation\. The apply holds every object of a later ` ekn.resourcePriority ` until the probe passes, for up to ` --ready-seconds `\. A probe that does not pass fails this object and all it holds\. For an admission policy, which the API server loads asynchronously and which has no status that says so\. Set it on the last object of a set, the binding: a policy acts only once its binding exists, and a probe on the policy holds its own binding back\. The validation harness ignores it\. *Type:* null or (submodule) *Default:* ```nix null ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.probe\.denied In effect when the dry-run is refused with this substring in the message\. For a validating policy or a webhook\. Use a string only this object says, such as its name: a Pod Security refusal also refuses\. *Type:* null or string *Default:* ```nix null ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.probe\.matches In effect when the dry-run is admitted and the stored object contains this partial object\. Lists compare item by item and must have the same length\. For a mutating policy\. *Type:* null or (attribute set of anything) *Default:* ```nix null ``` ## kubernetes\.objects\.\\.\\.\\.ekn\.probe\.object The manifest to server-dry-run\. It must pass validation and Pod Security in its namespace, its namespace must sort before this object, and its name must not exist\. *Type:* attribute set of anything *Default:* ```nix { } ``` ## kubernetes\.objects\.\\.\\.\\.kind The object’s kind\. *Type:* string *Default:* the attribute name above the object ## kubernetes\.objects\.\\.\\.\\.metadata The object’s metadata\. Other fields than these pass through as written\. ` namespace ` is set from the attribute name above the kind, except under ` none `\. *Type:* open submodule of (Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support)) *Default:* ```nix { } ``` ## kubernetes\.objects\.\\.\\.\\.metadata\.annotations The object’s annotations\. *Type:* (attribute set of ((string or signed integer convertible to it) or boolean convertible to it)) or value \ (singular enum) convertible to it *Default:* ```nix { } ``` ## kubernetes\.objects\.\\.\\.\\.metadata\.labels The object’s labels\. *Type:* (attribute set of ((string or signed integer convertible to it) or boolean convertible to it)) or value \ (singular enum) convertible to it *Default:* ```nix { } ``` ## kubernetes\.objects\.\\.\\.\\.metadata\.name The object’s name\. *Type:* string *Default:* the object’s attribute name ## kubernetes\.rawFiles Escape hatch from the module system for objects that must reach the cluster/git byte-identical to how they exist on disk – the normal ` kubernetes.resources ` -> ` generated ` pipeline round-trips every object through Nix’s own attrset representation, which ` builtins.toJSON ` always serializes with alphabetized keys, and which gains new sibling fields (` ekn `, ` metadata ` merged in by a module, etc\.) that weren’t present when the object was first authored\. Both of those permanently invalidate a SOPS whole-document MAC computed before either happened – fine for ` ekn kubeapply `’s own decrypt (` ekn.sops.maybe_decrypt ` passes ` --ignore-mac `, since each field’s own AES-GCM tag is still verified independently), but fatal for a MAC-verifying consumer that offers no such bypass (e\.g\. ArgoCD’s ksops-enabled repo-server)\. A raw file sidesteps the round-trip entirely: it must already be the complete manifest from before it was SOPS-encrypted, so nothing about its structure changes between encryption and decryption\. *Type:* list of (submodule) *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.rawFiles\.\*\.deploymentUnit Same routing as ekn\.deploymentUnit on a normal object – which deployment\.units entry this file belongs to\. Null omits it from every deploymentUnits entry (still kubeapply-able via the full kubernetes\.rawFiles list, just never committed to a GitOps branch)\. A raw file gets none of its unit’s ` labels `/` annotations `\. Nix never parses it – that is the whole point of a raw file – so there is nothing here to stamp\. Write any label you want into the file\. ` ekn.dev/deployment-unit ` is the exception, and ` ekn ` adds it at apply time (see ` _raw_manifest_in_unit ` in ekn/src/ekn/eval\.py)\. It is the prune scope, and a routed object without it is deleted by the next whole-instance ` --prune `: that selector excludes the hand-applied units by label value, and ` notin ` matches an object with no such label at all\. ` ekn commit ` still writes the file byte-identical\. *Type:* null or string *Default:* ```nix null ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.rawFiles\.\*\.path A complete, already-rendered Kubernetes manifest file (JSON or YAML, apiVersion/kind/metadata all present)\. Tracked as a Nix input (so it’s pinned/reproducible like everything else), but never parsed into ` resources `/` generated ` – ` ekn kubeapply `/` ekn commit ` read it directly instead\. For the same reason it carries no ` ekn.dev/manifest-hash ` unless the file holds one, so ` ekn kubeapply ` applies it on every run\. *Type:* absolute path *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.resources Alias of ` kubernetes.objects `\. *Type:* attribute set of open submodule of attribute set of open submodule of attribute set of open submodule of (Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support)) with mkIfExists support with mkIfExists support with mkIfExists support *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.resources\.\\.\\.\\.apiVersion The object’s apiVersion\. Evaluation fails when it is not set and the kind has no ` kubernetes.apiMappings ` entry\. *Type:* string *Default:* the ` kubernetes.apiMappings ` entry of the object’s kind ## kubernetes\.resources\.\\.\\.\\.ekn EKN-only metadata for this Kubernetes object\. *Type:* submodule *Default:* ```nix { } ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.after Objects that must exist before ` ekn kubeapply --converge ` creates this one\. Rendered as the ` kappy.dev/after ` annotation; the converging apply holds the object, without sending it, until each exists, for up to ` --wait-seconds `\. For what the API server accepts and a controller then abandons: a CloudNativePG Cluster created before its managed role’s password Secret records the role as unreconcilable and never retries it\. A dependency may be something no render contains, such as a Secret a controller writes\. Creation only: an object that already exists is applied whatever its dependencies are doing\. The barrier apply and the validation harness ignore it\. *Type:* list of (submodule) *Default:* ```nix [ ] ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.after\.\*\.apiVersion The apiVersion of the object to wait for\. *Type:* string ## kubernetes\.resources\.\\.\\.\\.ekn\.after\.\*\.kind The kind of the object to wait for\. *Type:* string ## kubernetes\.resources\.\\.\\.\\.ekn\.after\.\*\.name The name of the object to wait for\. *Type:* string ## kubernetes\.resources\.\\.\\.\\.ekn\.after\.\*\.namespace Null for a cluster-scoped object\. *Type:* null or string *Default:* ```nix null ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.deploymentUnit Name of the ` deployment.units. ` this object routes to\. Deliberately single-valued, not a list: an object synced by two GitOps targets at once means two controllers independently reconciling (and potentially pruning) the same resource\. The field itself is EKN-only and is stripped before Kubernetes manifests are rendered\. Its *value* is not: the object’s copy in ` kubernetes.deploymentUnits ` carries it in the ` ekn.dev/deployment-unit ` label, so the unit an object belongs to survives to the cluster whatever applies it\. The copy in ` kubernetes.generated ` is unstamped, as it is for every other per-unit label\. *Type:* null or string *Default:* ```nix null ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.novalidate Skip this object in ` ekn validate `’s ephemeral etcd+kube-apiserver harness\. For objects that can never be meaningfully verified there regardless of manifest correctness – e\.g\. an aggregated APIService, whose backing Service/Pod never actually runs in a throwaway, single-shot apiserver with no controllers or kubelets, so the apiserver 500s/503s on it (or on discovery calls that touch it) no matter what\. Applied for real via ` ekn kubeapply `/GitOps as normal; this only affects the validation harness\. *Type:* boolean *Default:* ```nix false ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.probe How ` ekn kubeapply ` sees that this object is in effect: a server dry-run and the answer it must give\. Exactly one of ` matches ` and ` denied `\. Rendered as the ` kappy.dev/probe ` annotation\. The apply holds every object of a later ` ekn.resourcePriority ` until the probe passes, for up to ` --ready-seconds `\. A probe that does not pass fails this object and all it holds\. For an admission policy, which the API server loads asynchronously and which has no status that says so\. Set it on the last object of a set, the binding: a policy acts only once its binding exists, and a probe on the policy holds its own binding back\. The validation harness ignores it\. *Type:* null or (submodule) *Default:* ```nix null ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.probe\.denied In effect when the dry-run is refused with this substring in the message\. For a validating policy or a webhook\. Use a string only this object says, such as its name: a Pod Security refusal also refuses\. *Type:* null or string *Default:* ```nix null ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.probe\.matches In effect when the dry-run is admitted and the stored object contains this partial object\. Lists compare item by item and must have the same length\. For a mutating policy\. *Type:* null or (attribute set of anything) *Default:* ```nix null ``` ## kubernetes\.resources\.\\.\\.\\.ekn\.probe\.object The manifest to server-dry-run\. It must pass validation and Pod Security in its namespace, its namespace must sort before this object, and its name must not exist\. *Type:* attribute set of anything *Default:* ```nix { } ``` ## kubernetes\.resources\.\\.\\.\\.kind The object’s kind\. *Type:* string *Default:* the attribute name above the object ## kubernetes\.resources\.\\.\\.\\.metadata The object’s metadata\. Other fields than these pass through as written\. ` namespace ` is set from the attribute name above the kind, except under ` none `\. *Type:* open submodule of (Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support)) *Default:* ```nix { } ``` ## kubernetes\.resources\.\\.\\.\\.metadata\.annotations The object’s annotations\. *Type:* (attribute set of ((string or signed integer convertible to it) or boolean convertible to it)) or value \ (singular enum) convertible to it *Default:* ```nix { } ``` ## kubernetes\.resources\.\\.\\.\\.metadata\.labels The object’s labels\. *Type:* (attribute set of ((string or signed integer convertible to it) or boolean convertible to it)) or value \ (singular enum) convertible to it *Default:* ```nix { } ``` ## kubernetes\.resources\.\\.\\.\\.metadata\.name The object’s name\. *Type:* string *Default:* the object’s attribute name ## kubernetes\.sopsAgeIdentities SOPS age decrypt identities some GitOps engine needs mounted as a Secret before it can sync anything referencing them (e\.g\. ArgoCD’s ksops-enabled repo-server, see argocd\.nix’s ` ksops.enable `)\. Purely additive metadata – any module wanting this generic bootstrap behavior appends an entry here instead of hand-rolling its own bootstrap script\. ` ekn kubeapply ` ensures each declared identity exists (generating a fresh age keypair the first time one is missing) before applying, and – when ` sopsConfigFile ` is set – registers the public key as a recipient there and re-runs ` sops updatekeys ` on ` sopsFiles `, aborting the whole apply rather than proceeding half-configured if either step fails\. This is the one place ekn actually generates key material – everywhere else, ekn only ever decrypts what SOPS already produced (see ` ekn.sops.maybe_decrypt `)\. *Type:* list of (submodule) *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.sopsAgeIdentities\.\*\.key Key within the Secret’s data the age identity is stored under\. *Type:* non-empty string *Default:* ```nix "key.txt" ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.sopsAgeIdentities\.\*\.namespace Namespace the identity Secret lives in\. *Type:* non-empty string *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.sopsAgeIdentities\.\*\.secretName Name of the Secret holding the age identity\. *Type:* non-empty string *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.sopsAgeIdentities\.\*\.sopsConfigFile Path to the ` .sops.yaml ` this identity’s age public key should be registered in as a recipient (idempotent – skipped if already present in every matching creation rule)\. Null (the default) leaves ` .sops.yaml ` untouched; the public key is only logged for manual handling\. *Type:* null or absolute path *Default:* ```nix null ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.sopsAgeIdentities\.\*\.sopsFiles Already-SOPS-encrypted files to run ` sops updatekeys ` on after the recipient is added to ` sopsConfigFile `, so their data key gets rewrapped for the new identity too\. Only consulted when ` sopsConfigFile ` is set\. *Type:* list of absolute path *Default:* ```nix [ ] ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.templates Typed resource template functions, usually created with the Adios-backed ` template ` helper\. *Type:* attribute set of function that evaluates to a(n) (Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support)) *Default:* ```nix { } ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## kubernetes\.transformers List of functions that transform object attrsets *Type:* list of function that evaluates to a(n) (attribute set) *Default:* ```nix [ ] ``` *Example:* ```nix '' kubernetes.transformers = [ ( object: # Apply annotations to all LoadBalancers if object.kind == "Service" && object.spec.type or null == "LoadBalancer" then lib.recursiveUpdate object { # IPv4 is scarce, share! metadata.annotations."metallb.io/allow-shared-ip" = "true"; # Lowest TTL cloudflare allows metadata.annotations."external-dns.alpha.kubernetes.io/ttl" = "60"; } # Make all services require dualstack else if object.kind == "Service" then lib.recursiveUpdate object { spec.ipFamilyPolicy = "RequireDualStack"; } # Set lowest cloudflare TTL for ingress and gapi routes else if lib.elem object.kind [ "Ingress" "HTTPRoute" ] then lib.recursiveUpdate object { metadata.annotations."external-dns.alpha.kubernetes.io/ttl" = "60"; } else object ) ]; '' ``` *Declared by:* - [easykubenix/kubernetes\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/kubernetes.nix) ## validation\.debug Whether to enable validation debugging\. *Type:* boolean *Default:* ```nix false ``` *Example:* ```nix true ``` *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix) ## validation\.etcdPackage The etcd package to use\. *Type:* package *Default:* ```nix pkgs.etcd ``` *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix) ## validation\.kubeadmConfig The kubeadm ClusterConfiguration that makes the validation harness’s certificates\. Every default is ` mkDefault `, so a definition here replaces one field and keeps the rest\. *Type:* Kubernetes-shaped JSON value (plain JSON, plus explicit mkNamedList/mkNumberedList/mkReplaceList/mkReplaceWhere override-by-name/index/prefix/predicate support) *Default:* ```nix null ``` *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix) ## validation\.openapiSpec A directory of Kubernetes OpenAPI v3 group-version documents, in the layout of the Kubernetes source tree’s ` api/openapi-spec/v3 `\. ` validation.schemaCheck ` and ` ekn schemacheck --offline ` read the built-in kinds’ schemas from it\. *Type:* string *Default:* ```nix "${config.kubernetes.package.src}/api/openapi-spec/v3" ``` *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix) ## validation\.podSubnet The pod CIDR the validation harness gives kubeadm\. *Type:* string *Default:* ```nix "10.97.0.0/16" ``` *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix) ## validation\.schemaCheck A build that checks every rendered object against its JSON schema: built-in kinds from ` validation.openapiSpec `, custom resources from the CRDs in the same render, with the CRDs’ CEL rules\. Rendered ValidatingAdmissionPolicies and their bindings are evaluated against the objects they match\. No network and no API server, so it runs in the build sandbox\. It fails on any violation, and lists the objects whose kind it has no schema for\. *Type:* package *(read only)* *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix) ## validation\.serviceSubnet The service CIDRs of the validation harness, comma-separated\. The API server’s ` --service-cluster-ip-range ` and the kubeadm certificates both use it\. *Type:* string *Default:* the CIDRs of ` kubernetes.clusterInfo.serviceCidr `, IPv4 first *Declared by:* - [easykubenix/validation\.nix](https://github.com/nixidae/easykubenix/blob/main/easykubenix/validation.nix)