-
Notifications
You must be signed in to change notification settings - Fork 295
Description
Feature Description
Issue Description:
Is your feature request related to a problem? Please describe.
Currently, when defining a ResourceGraphDefinition, handling optional fields within a resource template is verbose, error-prone, and in some cases, functionally impossible.
If a field in the schema.spec is optional (e.g., lifecycleRules or policy), we must currently use complex CEL ternary expressions to conditionally include it.
The Critical Issue (Validation Failures):
The standard workaround uses a ternary operator to return a "default" value when the field is missing:
# Current workaround attempts to pass an empty string if the property is missing
policy: '${has(schema.spec.policy) ? schema.spec.policy : ""}'
However, many Kubernetes controllers and CRDs do not accept empty strings or null values for specific fields.
- Example: The AWS ACK S3Bucket controller validates the
policyfield. If I pass an empty string ("") because the user didn't provide a policy, the underlying CRD validation fails (e.g.,InvalidPolicy: Policy cannot be empty). - Result: The resource cannot be created.
There is currently no clean way in kro to completely omit a field key from the generated manifest based on a condition. We are forced to generate the key with an invalid "empty" value.
Describe the solution you'd like
I propose introducing a dedicated syntax or directive for conditional field inclusion within the template section. This would allow defining a condition (CEL expression) that, if true, includes the field. If false, the field key is completely omitted from the generated YAML.
Proposed Syntax (Conceptual):
resources:
- id: bucket
template:
apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
spec:
name: ${schema.spec.bucketName}
# Proposed: Only generate the "policy" key if the schema has it.
# Otherwise, the "policy" key does not exist in the output manifest.
policy:
$kro.includeWhen: '${has(schema.spec.policy)}'
value: '${schema.spec.policy}'
# Example for complex objects
lifecycle:
$kro.includeWhen: '${has(schema.spec.lifecycleRules)}'
value:
rules: '${schema.spec.lifecycleRules}'
Describe alternatives you've considered
- Ternary Operators:
${has(x) ? x : ""}. As mentioned, this fails for CRDs that validate format (like IAM policies, ARNs, or Enums) and reject empty strings. - Complex JSON Construction: Writing raw JSON strings inside the CEL expression to reconstruct the entire parent object. This is extremely difficult to read and maintain.
Additional Context
In the attached module (S3 Bucket), fields like policy are optional strings. If the user does not provide a policy, we need the generated Bucket resource to look like this:
spec:
name: my-bucket
# policy key is missing entirely
Instead of this (which causes errors):
spec:
name: my-bucket
policy: ""