Parameters#
Parameters bridge the provider's Template and the consumer's TemplateInstance. The provider declares what the template accepts; the consumer supplies values. The operator resolves the merge at render time.
Two sides#
Parameters appear in two places:
Template.spec.parameters: provider-side declarations. Each declares a parameter name and may set a literal default, a type, and override rules.TemplateInstance.spec.parameters: consumer-side overrides. Each is either a literalvalueor a dynamicvalueFromthat resolves at render time.
A parameter name in the instance must match a name declared on the Template. Unknown names are rejected with ParametersValid=False, Reason=InvalidParameter.
Resolution#
For each parameter declared on the Template:
- If the
TemplateInstanceoverrides it, the override is resolved (literal orvalueFrom). - Otherwise the
Template'svaluedefault is used. - If neither exists, the parameter resolves to an empty value (
"", or[]/{}for anarray/objecttype). Arequiredparameter without an override fails instead, withParametersValid=False, Reason=InvalidParameter.
Resolution is fail-fast: if any single parameter can't be resolved, the entire TemplateInstance does not render. Rendering with missing parameter values would produce non-deterministic manifests that are rarely safe to apply.
Provider-side declarations#
A TemplateParameterDefinition is the shape of one entry in Template.spec.parameters.
| Field | Purpose |
|---|---|
name |
Required. Must be unique within the Template. |
value |
Optional literal default. |
type |
Optional. One of string, number, bool, array, object. Validates both the default and any instance override. |
required |
Optional. When true, the TemplateInstance MUST provide a value (the Template default, if any, is ignored). |
disableOverride |
Optional. When true, the TemplateInstance MUST NOT supply its own value. |
exposeInStatus |
Optional. When true, the resolved value is recorded in status.resolvedParameters[].value. |
required and disableOverride cannot both be true
The combination is rejected by CRD-level validation. required demands a consumer override; disableOverride forbids one.
type and what it validates#
type is a validation hint:
string: any value is accepted.number: must parse via Go'sstrconv.ParseFloat(e.g."3","3.14","-2.5e10"are accepted;"three"is rejected).bool: must parse viastrconv.ParseBool(e.g."true","false","1","0"are accepted;"yes"is rejected).array/object: the value must be a JSON array / object. A plain string never satisfies them.
Important
When an objectFieldRef resolves to a list or map, it cannot satisfy a scalar type such as string. Use array or object for those.
required semantics#
A required: true parameter forces the consumer to override it. Even if the Template has a value default, the default is ignored; the consumer must supply a value.
Usage: for values the consumer must consciously choose, such as database hostnames, TLS certificate names, or namespace selectors. Avoid required for parameters that already have safe defaults, since it forces every TemplateInstance to redeclare values the Template could have provided.
disableOverride semantics#
A disableOverride: true parameter is read-only from the consumer's point of view. An attempted override surfaces as ParametersValid=False, Reason=OverrideNotAllowed.
Usage: for values the platform team owns, such as image registries, mandatory labels, or security-relevant settings.
exposeInStatus semantics#
By default status.resolvedParameters[] only records the source of each parameter (which literal, or which valueFrom). The resolved value itself is not written to status; useful when values may be secrets.
exposeInStatus: true opts a specific parameter into having its resolved value written to status.resolvedParameters[].value.
Warning
exposeInStatus: true should be treated as a declaration that the parameter's value is public information. Never set it on parameters resolved from a Secret.
Instance-side overrides#
A TemplateParameter on the TemplateInstance has three shapes:
- Literal:
value: "...". - Dynamic:
valueFrom: { ... }reading from a cluster resource. - Dynamic with fallback:
valueFrom: { ... }plusdefaultValue: "...".
Validation rules#
The CRD rejects a TemplateInstance parameter that:
- Sets neither, or both, of
valueandvalueFrom. - Sets
defaultValuewithoutvalueFrom. - Sets both
valueanddefaultValue.
valueFrom.secretKeyRef and configMapKeyRef#
Read a specific key from a Secret or ConfigMap. Secret values are base64-decoded automatically. namespace is optional and defaults to the TemplateInstance's namespace.
valueFrom:
secretKeyRef:
name: db-credentials
key: password
objectFieldRef (GET vs LIST)#
objectFieldRef evaluates a JSONPath against any cluster resource, identified by GVK.
GET mode, when name is set, the operator GETs that one resource and evaluates the JSONPath against it. Returns a scalar.
valueFrom:
objectFieldRef:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: my-ingress
namespace: team-a
jsonPath: .status.loadBalancer.ingress[0].ip
LIST mode, when name is omitted, the operator LISTs all resources of the GVK and evaluates the JSONPath against the list. Always returns a list, even for single matches, so templates can {{range}} safely.
valueFrom:
objectFieldRef:
apiVersion: v1
kind: ConfigMap
namespace: team-alpha
jsonPath: .items[*].metadata.name
Namespace scoping for objectFieldRef:
- Set → operate in that namespace only.
- Omitted → for namespaced GVKs, operate across all namespaces; for cluster-scoped GVKs, the field is ignored.
GET mode always requires a namespace for namespaced GVKs.
JSONPath rules:
- Must start with a dot (
.metadata.name). - Do not wrap in
{}; the operator wraps it internally.
defaultValue semantics#
defaultValue is used only when paired with valueFrom, and applies whenever the valueFrom resolution fails for any reason: the resource doesn't exist, the key is missing, the GVK can't be mapped, the JSONPath matches nothing, and so on.
valueFrom:
secretKeyRef:
name: db-credentials
key: password
defaultValue: changeme
Secretdoesn't exist → resolution fails →changemeis used.Secretexists but thepasswordkey is missing → resolution fails →changemeis used.Secretexists, key exists, value is""→ resolution succeeds with an empty value, which is used as-is.defaultValueis not applied to successfully-resolved empty values.
Watch semantics#
For every valueFrom source, the operator registers a watch via its dynamic informer registry. Changes to the source trigger re-reconciliation of the TemplateInstance. This is how secret rotation, ConfigMap edits, and ingress IP assignment propagate without a manual kubectl edit.
This applies to sync.mode: revert and strict only. With sync.mode: off, the instance freezes after its first clean apply: the parameter watches are released, and source changes no longer propagate — see Sync.
If the GVK referenced by an objectFieldRef cannot be resolved (for example, a CRD that isn't installed), the operator skips setting up a watch for that source. Parameter resolution will still fail at reconcile time, surfaced as ParametersValid=False, Reason=ParameterResolutionFailed.
RBAC#
The operator's service account needs get, list, and watch on every GVK referenced by objectFieldRef. The chart grants only Namespace reads: grant every kind referenced by secretKeyRef, configMapKeyRef, or objectFieldRef through the chart's rbac.additionalRules. See Granting permissions to rendered kinds.
See also#
- Parameters and overrides for examples.
- Parameter validation for guidance on choosing
type/required/disableOverride/exposeInStatus. - API reference:
TemplateParameterDefinitionandTemplateParameter.