Traits

traits

Traits are high level named features of Camel K that can be enabled/disabled or configured to customize the behavior of the final Integration. You can think a trait as a possible way to tune your Integration on the running platform. Through the configuration of a trait, you will be able to specify certain characteristics configuring low level details, if you need to.

Advanced users will find it very useful to configure certain facets of the deployments or to control how to manage the cluster resources. Most of the time you need to interact with the cluster, you will need to configure a trait that control such cluster behavior (think at the Pod, Container, Service traits which map to the Kubernetes resources of the same name).

This page is dedicated to developers/engineers willing to dive more in the low level details of Camel K development. You can find a complete list of available traits and how to configure them in the trait section.

This document reflects Camel K version 1.5. It may not reflect slight changes developed after this review.

Traits life cycle

Traits are typically used to tune several aspects of an Integration. However, you will learn that we are using the same concept to influence the build of IntegrationKits. Therefore, we can distinguish between those traits that can be applied to either one or the other type. Another important thing to know is that the platform uses this mechanism to perform many common (hidden to the user) operations. We use to identify those trait as platform traits. Misusing a platform trait may result in execution errors.

Another important concept related to the trait lifecycle is the trait profile. At this time, Camel K supports the following profiles:

  • Kubernetes

  • OpenShift

  • Knative

A profile is useful to identify on which kind of cluster a trait has to run: vanilla Kubernetes, OpenShift or OpenShift/Kubernetes clusters powered by Knative. The default is to allow a trait on any profile; each trait can specify a different behavior (ie, running a trait only for a profile as it happens with Knative).

Trait configuration

A Camel K user will provide a trait configuration via CLI (--trait or -t flag) or setting directly its configuration into the Integration resource. Each trait has a unique id and can expose any kind of parameter ie, kamel run -t [trait-id].[key]=[value]. The operator will transform that key and value in the related trait variable. You can have a further look at the configuration details.

Trait interface

In order to understand the logic behind the trait management better, let’s have a look at the Trait interface:

type Trait interface {
	Identifiable
	client.Injectable
	InjectContext(context.Context)
	Configure(environment *Environment) (bool, TraitCondition, error)
	Apply(environment *Environment) error
	InfluencesKit() bool
	InfluencesBuild(this, prev map[string]interface{}) bool
	IsPlatformTrait() bool
	RequiresIntegrationPlatform() bool
	IsAllowedInProfile(v1.TraitProfile) bool
	Order() int
}

Each trait will implement this interface. The most important methods that will be invoked by the Operator are Configure() and Apply(). Basically, the Configure() method will set those inputs aforementioned (each trait has its own). The method is in charge to verify also the correctness of those expected parameters, where it makes sense (i.e., a well expected Kubernetes resource name). The function can return a TraitCondition object containing any informative or warning condition to be attached to the resulting Integration (for instance, traits forcefully altered by the platform, or deprecation notices).

Once configured, the Apply() method will be called along the build or initialization phase in order to do the business logic expected for it. The environment variable will give you all the below resources you will need to perform your operation (ie, the Integration or any Kubernetes resource attached to it). You can have a deeper look at the Environment struct.

The Order() method helps in resolving the order of execution of different traits. As every trait can be expected to be run before or after another trait, or any other controller operation.

The InfluencesKit(), IsPlatformTrait() and RequiresIntegrationPlatform() methods are easy to understand. They are used to determine if a trait has to influence an IntegrationKit build/initialization, if it’s a platform trait (ie, needed by the platform itself) or are requiring the presence of an IntegrationPlatform.

The presence of InfluencesBuild() will let specify the level of granularity of a trait down to its properties for a rebuild. So, if you need, you can compare the traits properties coming from the prev (previous) Integration to decide if it is worth to rebuild an Integration or the trait can reuse the one already provided in this version.

Finally, through the IsAllowedInProfile() method we can override the default behavior (allow the trait for any profile). We must specify the profile we expect for this trait to be executed properly.