Skip to main content
Version: v1.0.0-rc.1 (pre-release)

Trait

A Trait represents a cross-cutting concern that can be attached to components to add additional capabilities like persistent storage, observability, security policies, or service mesh integration. Traits modify or extend the resources generated by ComponentTypes without requiring changes to the ComponentType itself.

API Version​

openchoreo.dev/v1alpha1

Resource Definition​

Metadata​

Traits are namespace-scoped resources typically created in a namespace to be available for components in that namespace.

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: <trait-name>
namespace: <namespace> # Namespace for grouping traits

Short names: trait, traits

Spec Fields​

FieldTypeRequiredDefaultDescription
parametersSchemaSectionNo-Developer-facing configurable parameters for this trait
environmentConfigsSchemaSectionNo-Parameters that can be overridden per environment
validations[ValidationRule]No[]CEL-based rules evaluated during rendering; all must pass for rendering to proceed
creates[TraitCreate]No[]New Kubernetes resources to create
patches[TraitPatch]No[]Modifications to existing ComponentType resources

SchemaSection​

Defines the schema for configurable parameters using standard JSON Schema.

FieldTypeRequiredDefaultDescription
openAPIV3SchemaobjectNo-Standard OpenAPI v3 JSON Schema for defining parameters

Example:

parameters:
openAPIV3Schema:
type: object
properties:
volumeName:
type: string
mountPath:
type: string
containerName:
type: string
default: "app"

environmentConfigs:
openAPIV3Schema:
type: object
properties:
size:
type: string
default: "10Gi"
storageClass:
type: string
default: "standard"

TraitCreate​

Defines a new Kubernetes resource to be created when the trait is applied.

FieldTypeRequiredDefaultDescription
targetPlanestringNodataplaneTarget plane: dataplane or observabilityplane
includeWhenstringNo-CEL expression determining if resource should be created
forEachstringNo-CEL expression for generating multiple resources from list
varstringNo-Variable name for forEach iterations (required if forEach is set)
templateobjectYes-Kubernetes resource template with CEL expressions

CEL expressions in trait templates have access to the following context variables:

metadata​

Platform-computed metadata for resource generation (same as ComponentType):

FieldTypeDescription
metadata.namestringBase name for generated resources (e.g., my-service-dev-a1b2c3d4)
metadata.namespacestringTarget namespace for resources
metadata.componentNamespacestringTarget namespace of the component
metadata.componentNamestringName of the component
metadata.componentUIDstringUnique identifier of the component
metadata.projectNamestringName of the project
metadata.projectUIDstringUnique identifier of the project
metadata.environmentNamestringName of the environment (e.g., development, production)
metadata.environmentUIDstringUnique identifier of the environment
metadata.dataPlaneNamestringName of the data plane
metadata.dataPlaneUIDstringUnique identifier of the data plane
metadata.labelsmapCommon labels to add to all resources
metadata.annotationsmapCommon annotations to add to all resources
metadata.podSelectorsmapPlatform-injected selectors for pod identity
trait​

Trait-specific metadata:

FieldTypeDescription
trait.namestringName of the trait (e.g., persistent-volume)
trait.instanceNamestringUnique instance name within the component (e.g., data-storage)
parameters​

Trait instance parameters from Component.spec.traits[].parameters with schema defaults applied. Use for static configuration that doesn't change across environments.

environmentConfigs​

Environment-specific configuration from ReleaseBinding.spec.traitEnvironmentConfigs[instanceName] with schema defaults applied. Use for values that vary per environment.

dataplane​

Data plane configuration:

FieldTypeDescription
dataplane.secretStorestringName of the ClusterSecretStore for external secrets
dataplane.publicVirtualHoststringPublic virtual host for external access
Helper Functions​
FunctionDescription
oc_generate_name(args...)Generate valid Kubernetes names with hash suffix for uniqueness
oc_hash(string)Generate 8-character FNV-32a hash from input string
oc_merge(map1, map2, ...)Shallow merge maps (later maps override earlier ones)
oc_omit()Remove field/key from output when used in conditional expressions
oc_dns_label(args...)Generate RFC 1123-compliant DNS label (≀63 chars) with hash suffix for HTTPRoute hostnames

TraitPatch​

Defines modifications to existing resources generated by the ComponentType.

FieldTypeRequiredDefaultDescription
forEachstringNo-CEL expression for iterating over a list
varstringNo-Variable name for forEach iterations (required if forEach set)
targetPatchTargetYes-Specifies which resource to patch
targetPlanestringNodataplaneTarget plane: dataplane or observabilityplane
operations[JSONPatchOperation]Yes-List of JSONPatch operations to apply

PatchTarget​

Specifies which Kubernetes resource to modify.

FieldTypeRequiredDescription
groupstringYesAPI group (e.g., apps, batch). Use empty string "" for core resources
versionstringYesAPI version (e.g., v1, v1beta1)
kindstringYesResource type (e.g., Deployment, StatefulSet)
wherestringNoCEL expression to filter which resources to patch

JSONPatchOperation​

Defines a modification using JSONPatch format (RFC 6902) with OpenChoreo extensions.

FieldTypeRequiredDescription
opstringYesOperation: add, replace, remove
pathstringYesJSON Pointer to the field (RFC 6901)
valueanyNoValue to set (not used for remove)

Supported Operations​

  • add: Add a new field or array element
  • replace: Replace an existing field value
  • remove: Delete a field

Path Syntax​

Supports array filters for targeting specific elements:

/spec/containers[?(@.name=='app')]/volumeMounts/-

Examples​

Persistent Volume Trait​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: persistent-volume
namespace: default
spec:
parameters:
openAPIV3Schema:
type: object
properties:
volumeName:
type: string
mountPath:
type: string
containerName:
type: string
default: "app"

environmentConfigs:
openAPIV3Schema:
type: object
properties:
size:
type: string
default: "10Gi"
storageClass:
type: string
default: "standard"

creates:
- template:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ${metadata.name}-${trait.instanceName}
namespace: ${metadata.namespace}
spec:
accessModes:
- ReadWriteOnce
storageClassName: ${environmentConfigs.storageClass}
resources:
requests:
storage: ${environmentConfigs.size}

patches:
- target:
group: apps
version: v1
kind: Deployment
operations:
- op: add
path: /spec/template/spec/containers[?(@.name=='${parameters.containerName}')]/volumeMounts/-
value:
name: ${parameters.volumeName}
mountPath: ${parameters.mountPath}
- op: add
path: /spec/template/spec/volumes/-
value:
name: ${parameters.volumeName}
persistentVolumeClaim:
claimName: ${metadata.name}-${trait.instanceName}

Sidecar Container Trait​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: logging-sidecar
namespace: default
spec:
parameters:
openAPIV3Schema:
type: object
properties:
logPath:
type: string
default: "/var/log/app"
sidecarImage:
type: string
default: "fluent/fluent-bit:latest"

patches:
- target:
group: apps
version: v1
kind: Deployment
operations:
- op: add
path: /spec/template/spec/containers/-
value:
name: log-collector
image: ${parameters.sidecarImage}
volumeMounts:
- name: logs
mountPath: ${parameters.logPath}
- op: add
path: /spec/template/spec/volumes/-
value:
name: logs
emptyDir: {}

Resource Limits Trait​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: resource-limits
namespace: default
spec:
environmentConfigs:
openAPIV3Schema:
type: object
properties:
cpuLimit:
type: string
default: "1000m"
memoryLimit:
type: string
default: "512Mi"

patches:
- target:
group: apps
version: v1
kind: Deployment
operations:
- op: add
path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/cpu
value: ${environmentConfigs.cpuLimit}
- op: add
path: /spec/template/spec/containers[?(@.name=='main')]/resources/limits/memory
value: ${environmentConfigs.memoryLimit}

Multi-Container Trait with forEach​

apiVersion: openchoreo.dev/v1alpha1
kind: Trait
metadata:
name: multi-volume
namespace: default
spec:
parameters:
openAPIV3Schema:
type: object
properties:
mounts:
type: array
items:
type: object
properties:
name:
type: string
path:
type: string

patches:
- target:
group: apps
version: v1
kind: Deployment
forEach: ${parameters.mounts}
var: mount
operations:
- op: add
path: /spec/template/spec/volumes/-
value:
name: ${mount.name}
emptyDir: {}
- op: add
path: /spec/template/spec/containers[?(@.name=='app')]/volumeMounts/-
value:
name: ${mount.name}
mountPath: ${mount.path}

Usage​

Developers attach traits to components in the Component specification:

apiVersion: openchoreo.dev/v1alpha1
kind: Component
metadata:
name: my-service
spec:
componentType:
kind: ComponentType
name: deployment/service

traits:
- name: persistent-volume
kind: Trait
instanceName: data-storage
parameters:
volumeName: data
mountPath: /var/data
containerName: app

Platform engineers can set trait environmentConfigs in ReleaseBinding:

apiVersion: openchoreo.dev/v1alpha1
kind: ReleaseBinding
metadata:
name: my-service-production
namespace: default
spec:
environment: production
owner:
componentName: my-service
projectName: default

traitEnvironmentConfigs:
data-storage: # keyed by instanceName
size: 100Gi
storageClass: production-ssd

Best Practices​

  1. Single Responsibility: Each trait should address one cross-cutting concern
  2. Naming: Use descriptive names that indicate the capability being added
  3. Parameters: Provide sensible defaults for all non-required parameters
  4. Target Specificity: Use where clauses when needed to avoid unintended modifications
  5. Testing: Test traits with different ComponentTypes to ensure compatibility
  6. Documentation: Document which ComponentTypes a trait is designed to work with
  7. Idempotency: Ensure traits can be safely applied multiple times

Trait vs ComponentType​

AspectComponentTypeTrait
PurposeDefines core deployment patternAdds cross-cutting concerns
ScopeOne per componentMultiple can be attached to one component
ResourcesCreates primary workload resourcesCreates supplementary resources or patches existing ones
ModificationDetermines base resource structureModifies or extends ComponentType resources
ExamplesService, WebApp, ScheduledTaskPersistent Storage, Logging, Security