Repository: apache/camel-k
Pull request #3417 (2022-07-06 08:53:08)

[Backport 1.9.x] Update to CronJob batch/v1
Manual backport of #3402 and #3411 

**Release Note**
```release-note
Chore(deps): Update CronJob from batch/v1beta1 to batch/v1
```


christophd: @tadayosi could you please respin the failing workflow. I want to see if this is a flaky test

Patch:
diff --git a/docs/modules/ROOT/pages/contributing/developers.adoc b/docs/modules/ROOT/pages/contributing/developers.adoc
index e4982ea97..ad3fe29dc 100644
--- a/docs/modules/ROOT/pages/contributing/developers.adoc
+++ b/docs/modules/ROOT/pages/contributing/developers.adoc
@@ -27,6 +27,7 @@ In order to build the project, you need to comply with the following requirement
 * **MinGW**: needed to compile the project on Windows. Refer to the https://www.mingw-w64.org/[MinGW website] for the installation.
 * **Windows Subsystem for Linux (WSL)**: for running Linux binary executables natively on Windows. Refer to https://docs.microsoft.com/en-us/windows/wsl/install[WSL Website] for installation. Alternatively, you can use https://www.cygwin.com/[Cygwin] or https://www.educative.io/edpresso/how-to-install-git-bash-in-windows[Git Bash].
 
+NOTE: MacOS users will need to use *gnu-sed* to successfully run the Make build scripts (e.g. for generating the Camel K bundle). Please install gnu-sed on your machine (e.g. `brew install gnu-sed`) and set your PATH accordingly to use gnu-sed with: `export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"`
 
 The Camel K Java runtime (camel-k-runtime) requires:
 
diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go
index c58db2d00..8a8ffa2a7 100644
--- a/pkg/cmd/operator/operator.go
+++ b/pkg/cmd/operator/operator.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"math/rand"
 	"os"
+	"reflect"
 	"runtime"
 	"strconv"
 	"time"
@@ -31,10 +32,10 @@ import (
 
 	appsv1 "k8s.io/api/apps/v1"
 	batchv1 "k8s.io/api/batch/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
 	coordination "k8s.io/api/coordination/v1"
 	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/fields"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/selection"
 	"k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -153,6 +154,22 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
 	exitOnError(err, "cannot create Integration label selector")
 	selector := labels.NewSelector().Add(*hasIntegrationLabel)
 
+	selectors := cache.SelectorsByObject{
+		&corev1.Pod{}:        {Label: selector},
+		&appsv1.Deployment{}: {Label: selector},
+		&batchv1.Job{}:       {Label: selector},
+		&servingv1.Service{}: {Label: selector},
+	}
+
+	if ok, err := kubernetes.IsAPIResourceInstalled(c, batchv1.SchemeGroupVersion.String(), reflect.TypeOf(batchv1.CronJob{}).Name()); ok && err == nil {
+		selectors[&batchv1.CronJob{}] = struct {
+			Label labels.Selector
+			Field fields.Selector
+		}{
+			Label: selector,
+		}
+	}
+
 	mgr, err := manager.New(c.GetConfig(), manager.Options{
 		Namespace:                     watchNamespace,
 		EventBroadcaster:              broadcaster,
@@ -165,13 +182,7 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
 		MetricsBindAddress:            ":" + strconv.Itoa(int(monitoringPort)),
 		NewCache: cache.BuilderWithOptions(
 			cache.Options{
-				SelectorsByObject: cache.SelectorsByObject{
-					&corev1.Pod{}:           {Label: selector},
-					&appsv1.Deployment{}:    {Label: selector},
-					&batchv1beta1.CronJob{}: {Label: selector},
-					&batchv1.Job{}:          {Label: selector},
-					&servingv1.Service{}:    {Label: selector},
-				},
+				SelectorsByObject: selectors,
 			},
 		),
 	})
diff --git a/pkg/cmd/trait_help.go b/pkg/cmd/trait_help.go
index b56e8c69e..0ef7bc9af 100644
--- a/pkg/cmd/trait_help.go
+++ b/pkg/cmd/trait_help.go
@@ -26,14 +26,12 @@ import (
 	"strings"
 
 	"github.com/fatih/structs"
-	"github.com/mitchellh/mapstructure"
 	"github.com/spf13/cobra"
 	"gopkg.in/yaml.v2"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/resources"
 	"github.com/apache/camel-k/pkg/trait"
-	"github.com/apache/camel-k/pkg/util"
 	"github.com/apache/camel-k/pkg/util/indentedwriter"
 )
 
@@ -263,108 +261,3 @@ func outputTraits(descriptions []*traitDescription) (string, error) {
 		return nil
 	})
 }
-
-func validateTraits(catalog *trait.Catalog, traits []string) error {
-	tp := catalog.ComputeTraitsProperties()
-	for _, t := range traits {
-		kv := strings.SplitN(t, "=", 2)
-		prefix := kv[0]
-		if strings.Contains(prefix, "[") {
-			prefix = prefix[0:strings.Index(prefix, "[")]
-		}
-		if !util.StringSliceExists(tp, prefix) {
-			return fmt.Errorf("%s is not a valid trait property", t)
-		}
-	}
-
-	return nil
-}
-
-func configureTraits(options []string, catalog trait.Finder) (map[string]v1.TraitSpec, error) {
-	traits := make(map[string]map[string]interface{})
-
-	for _, option := range options {
-		parts := traitConfigRegexp.FindStringSubmatch(option)
-		if len(parts) < 4 {
-			return nil, errors.New("unrecognized config format (expected \"<trait>.<prop>=<value>\"): " + option)
-		}
-		id := parts[1]
-		fullProp := parts[2][1:]
-		value := parts[3]
-		if _, ok := traits[id]; !ok {
-			traits[id] = make(map[string]interface{})
-		}
-
-		propParts := util.ConfigTreePropertySplit(fullProp)
-		var current = traits[id]
-		if len(propParts) > 1 {
-			c, err := util.NavigateConfigTree(current, propParts[0:len(propParts)-1])
-			if err != nil {
-				return nil, err
-			}
-			if cc, ok := c.(map[string]interface{}); ok {
-				current = cc
-			} else {
-				return nil, errors.New("trait configuration cannot end with a slice")
-			}
-		}
-
-		prop := propParts[len(propParts)-1]
-		switch v := current[prop].(type) {
-		case []string:
-			current[prop] = append(v, value)
-		case string:
-			// Aggregate multiple occurrences of the same option into a string array, to emulate POSIX conventions.
-			// This enables executing:
-			// $ kamel run -t <trait>.<property>=<value_1> ... -t <trait>.<property>=<value_N>
-			// Or:
-			// $ kamel run --trait <trait>.<property>=<value_1>,...,<trait>.<property>=<value_N>
-			current[prop] = []string{v, value}
-		case nil:
-			current[prop] = value
-		}
-	}
-
-	specs := make(map[string]v1.TraitSpec)
-	for id, config := range traits {
-		t := catalog.GetTrait(id)
-		if t != nil {
-			// let's take a clone to prevent default values set at runtime from being serialized
-			zero := reflect.New(reflect.TypeOf(t)).Interface()
-			err := configureTrait(config, zero)
-			if err != nil {
-				return nil, err
-			}
-			data, err := json.Marshal(zero)
-			if err != nil {
-				return nil, err
-			}
-			var spec v1.TraitSpec
-			err = json.Unmarshal(data, &spec.Configuration)
-			if err != nil {
-				return nil, err
-			}
-			specs[id] = spec
-		}
-	}
-
-	return specs, nil
-}
-
-func configureTrait(config map[string]interface{}, trait interface{}) error {
-	md := mapstructure.Metadata{}
-
-	decoder, err := mapstructure.NewDecoder(
-		&mapstructure.DecoderConfig{
-			Metadata:         &md,
-			WeaklyTypedInput: true,
-			TagName:          "property",
-			Result:           &trait,
-		},
-	)
-	if err != nil {
-		return err
-	}
-
-	return decoder.Decode(config)
-}
diff --git a/pkg/cmd/trait_support.go b/pkg/cmd/trait_support.go
new file mode 100644
index 000000000..63fa23b9c
--- /dev/null
+++ b/pkg/cmd/trait_support.go
@@ -0,0 +1,136 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cmd
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/trait"
+	"github.com/apache/camel-k/pkg/util"
+	"github.com/mitchellh/mapstructure"
+)
+
+func validateTraits(catalog *trait.Catalog, traits []string) error {
+	tp := catalog.ComputeTraitsProperties()
+	for _, t := range traits {
+		kv := strings.SplitN(t, "=", 2)
+		prefix := kv[0]
+		if strings.Contains(prefix, "[") {
+			prefix = prefix[0:strings.Index(prefix, "[")]
+		}
+		if !util.StringSliceExists(tp, prefix) {
+			return fmt.Errorf("%s is not a valid trait property", t)
+		}
+	}
+
+	return nil
+}
+
+func configureTraits(options []string, catalog trait.Finder) (map[string]v1.TraitSpec, error) {
+	traits := make(map[string]map[string]interface{})
+
+	for _, option := range options {
+		parts := traitConfigRegexp.FindStringSubmatch(option)
+		if len(parts) < 4 {
+			return nil, errors.New("unrecognized config format (expected \"<trait>.<prop>=<value>\"): " + option)
+		}
+		id := parts[1]
+		fullProp := parts[2][1:]
+		value := parts[3]
+		if _, ok := traits[id]; !ok {
+			traits[id] = make(map[string]interface{})
+		}
+
+		propParts := util.ConfigTreePropertySplit(fullProp)
+		var current = traits[id]
+		if len(propParts) > 1 {
+			c, err := util.NavigateConfigTree(current, propParts[0:len(propParts)-1])
+			if err != nil {
+				return nil, err
+			}
+			if cc, ok := c.(map[string]interface{}); ok {
+				current = cc
+			} else {
+				return nil, errors.New("trait configuration cannot end with a slice")
+			}
+		}
+
+		prop := propParts[len(propParts)-1]
+		switch v := current[prop].(type) {
+		case []string:
+			current[prop] = append(v, value)
+		case string:
+			// Aggregate multiple occurrences of the same option into a string array, to emulate POSIX conventions.
+			// This enables executing:
+			// $ kamel run -t <trait>.<property>=<value_1> ... -t <trait>.<property>=<value_N>
+			// Or:
+			// $ kamel run --trait <trait>.<property>=<value_1>,...,<trait>.<property>=<value_N>
+			current[prop] = []string{v, value}
+		case nil:
+			current[prop] = value
+		}
+	}
+
+	specs := make(map[string]v1.TraitSpec)
+	for id, config := range traits {
+		t := catalog.GetTrait(id)
+		if t != nil {
+			// let's take a clone to prevent default values set at runtime from being serialized
+			zero := reflect.New(reflect.TypeOf(t)).Interface()
+			err := configureTrait(config, zero)
+			if err != nil {
+				return nil, err
+			}
+			data, err := json.Marshal(zero)
+			if err != nil {
+				return nil, err
+			}
+			var spec v1.TraitSpec
+			err = json.Unmarshal(data, &spec.Configuration)
+			if err != nil {
+				return nil, err
+			}
+			specs[id] = spec
+		}
+	}
+
+	return specs, nil
+}
+
+func configureTrait(config map[string]interface{}, trait interface{}) error {
+	md := mapstructure.Metadata{}
+
+	decoder, err := mapstructure.NewDecoder(
+		&mapstructure.DecoderConfig{
+			Metadata:         &md,
+			WeaklyTypedInput: true,
+			TagName:          "property",
+			Result:           &trait,
+		},
+	)
+	if err != nil {
+		return err
+	}
+
+	return decoder.Decode(config)
+}
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 964adb18f..2ee389e2d 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -24,7 +24,7 @@ import (
 	"time"
 
 	appsv1 "k8s.io/api/apps/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -203,8 +203,6 @@ func add(mgr manager.Manager, c client.Client, r reconcile.Reconciler) error {
 			})).
 		// Watch for the owned Deployments
 		Owns(&appsv1.Deployment{}, builder.WithPredicates(StatusChangedPredicate{})).
-		// Watch for the owned CronJobs
-		Owns(&batchv1beta1.CronJob{}, builder.WithPredicates(StatusChangedPredicate{})).
 		// Watch for the Integration Pods
 		Watches(&source.Kind{Type: &corev1.Pod{}},
 			handler.EnqueueRequestsFromMapFunc(func(a ctrl.Object) []reconcile.Request {
@@ -223,6 +221,11 @@ func add(mgr manager.Manager, c client.Client, r reconcile.Reconciler) error {
 				}
 			}))
 
+	if ok, err := kubernetes.IsAPIResourceInstalled(c, batchv1.SchemeGroupVersion.String(), reflect.TypeOf(batchv1.CronJob{}).Name()); ok && err == nil {
+		// Watch for the owned CronJobs
+		b.Owns(&batchv1.CronJob{}, builder.WithPredicates(StatusChangedPredicate{}))
+	}
+
 	// Watch for the owned Knative Services conditionally
 	if ok, err := kubernetes.IsAPIResourceInstalled(c, servingv1.SchemeGroupVersion.String(), reflect.TypeOf(servingv1.Service{}).Name()); err != nil {
 		return err
diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go
index 91ea73f63..3e68a3a24 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -25,7 +25,7 @@ import (
 	"strconv"
 
 	appsv1 "k8s.io/api/apps/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/equality"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -185,9 +185,9 @@ func (action *monitorAction) newController(ctx context.Context, env *trait.Envir
 			integration: integration,
 		}
 	case isConditionTrue(integration, v1.IntegrationConditionCronJobAvailable):
-		obj = getUpdatedController(env, &batchv1beta1.CronJob{})
+		obj = getUpdatedController(env, &batchv1.CronJob{})
 		controller = &cronJobController{
-			obj:         obj.(*batchv1beta1.CronJob),
+			obj:         obj.(*batchv1.CronJob),
 			integration: integration,
 			client:      action.client,
 			context:     ctx,
diff --git a/pkg/controller/integration/monitor_cronjob.go b/pkg/controller/integration/monitor_cronjob.go
index 8a024df16..77bf162b8 100644
--- a/pkg/controller/integration/monitor_cronjob.go
+++ b/pkg/controller/integration/monitor_cronjob.go
@@ -22,7 +22,6 @@ import (
 	"fmt"
 
 	batchv1 "k8s.io/api/batch/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
 	corev1 "k8s.io/api/core/v1"
 
 	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
@@ -33,7 +32,7 @@ import (
 )
 
 type cronJobController struct {
-	obj              *batchv1beta1.CronJob
+	obj              *batchv1.CronJob
 	integration      *v1.Integration
 	client           client.Client
 	context          context.Context
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 0f61820e6..cc18bdf56 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -22,7 +22,7 @@ import (
 	"path"
 
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -297,7 +297,7 @@ func (t *containerTrait) configureContainer(e *Environment) error {
 	}
 
 	// CronJob
-	if err := e.Resources.VisitCronJobE(func(cron *v1beta1.CronJob) error {
+	if err := e.Resources.VisitCronJobE(func(cron *batchv1.CronJob) error {
 		for _, envVar := range e.EnvVars {
 			envvar.SetVar(&container.Env, envVar)
 		}
diff --git a/pkg/trait/cron.go b/pkg/trait/cron.go
index dbfeb556e..fb717118f 100644
--- a/pkg/trait/cron.go
+++ b/pkg/trait/cron.go
@@ -24,7 +24,6 @@ import (
 	"strings"
 
 	batchv1 "k8s.io/api/batch/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
@@ -172,7 +171,7 @@ func (t *cronTrait) Configure(e *Environment) (bool, error) {
 		}
 
 		if t.ConcurrencyPolicy == "" {
-			t.ConcurrencyPolicy = string(batchv1beta1.ForbidConcurrent)
+			t.ConcurrencyPolicy = string(batchv1.ForbidConcurrent)
 		}
 
 		if (t.Schedule == "" && t.Components == "") && t.Fallback == nil {
@@ -264,7 +263,7 @@ func (t *cronTrait) Apply(e *Environment) error {
 	return nil
 }
 
-func (t *cronTrait) getCronJobFor(e *Environment) *batchv1beta1.CronJob {
+func (t *cronTrait) getCronJobFor(e *Environment) *batchv1.CronJob {
 	annotations := make(map[string]string)
 	if e.Integration.Annotations != nil {
 		for k, v := range filterTransferableAnnotations(e.Integration.Annotations) {
@@ -282,10 +281,10 @@ func (t *cronTrait) getCronJobFor(e *Environment) *batchv1beta1.CronJob {
 		backoffLimit = *t.BackoffLimit
 	}
 
-	cronjob := batchv1beta1.CronJob{
+	cronjob := batchv1.CronJob{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "CronJob",
-			APIVersion: batchv1beta1.SchemeGroupVersion.String(),
+			APIVersion: batchv1.SchemeGroupVersion.String(),
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      e.Integration.Name,
@@ -295,11 +294,11 @@ func (t *cronTrait) getCronJobFor(e *Environment) *batchv1beta1.CronJob {
 			},
 			Annotations: e.Integration.Annotations,
 		},
-		Spec: batchv1beta1.CronJobSpec{
+		Spec: batchv1.CronJobSpec{
 			Schedule:                t.Schedule,
-			ConcurrencyPolicy:       batchv1beta1.ConcurrencyPolicy(t.ConcurrencyPolicy),
+			ConcurrencyPolicy:       batchv1.ConcurrencyPolicy(t.ConcurrencyPolicy),
 			StartingDeadlineSeconds: t.StartingDeadlineSeconds,
-			JobTemplate: batchv1beta1.JobTemplateSpec{
+			JobTemplate: batchv1.JobTemplateSpec{
 				Spec: batchv1.JobSpec{
 					ActiveDeadlineSeconds: &activeDeadline,
 					BackoffLimit:          &backoffLimit,
diff --git a/pkg/trait/mount.go b/pkg/trait/mount.go
index 6c8976a85..85b1f1742 100644
--- a/pkg/trait/mount.go
+++ b/pkg/trait/mount.go
@@ -23,7 +23,7 @@ import (
 	"strings"
 
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 
@@ -118,7 +118,7 @@ func (t *mountTrait) Apply(e *Environment) error {
 	}
 
 	// CronJob
-	if err := e.Resources.VisitCronJobE(func(cron *v1beta1.CronJob) error {
+	if err := e.Resources.VisitCronJobE(func(cron *batchv1.CronJob) error {
 		volumes = &cron.Spec.JobTemplate.Spec.Template.Spec.Volumes
 		visited = true
 		return nil
diff --git a/pkg/trait/pod.go b/pkg/trait/pod.go
index b3722f32b..b077328b0 100644
--- a/pkg/trait/pod.go
+++ b/pkg/trait/pod.go
@@ -21,7 +21,7 @@ import (
 	"fmt"
 
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/util/json"
 	"k8s.io/apimachinery/pkg/util/strategicpatch"
@@ -70,7 +70,7 @@ func (t *podTrait) Apply(e *Environment) error {
 	}
 	switch strategy {
 	case ControllerStrategyCronJob:
-		e.Resources.VisitCronJob(func(c *v1beta1.CronJob) {
+		e.Resources.VisitCronJob(func(c *batchv1.CronJob) {
 			if c.Name == e.Integration.Name {
 				if patchedPodSpec, err = t.applyChangesTo(&c.Spec.JobTemplate.Spec.Template.Spec, changes); err == nil {
 					c.Spec.JobTemplate.Spec.Template.Spec = *patchedPodSpec
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 492c3c22d..a53ec9841 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -27,7 +27,7 @@ import (
 	"github.com/pkg/errors"
 
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
@@ -326,7 +326,7 @@ func (e *Environment) GetIntegrationPodSpec() *corev1.PodSpec {
 	}
 
 	// Cronjob
-	cronJob := e.Resources.GetCronJob(func(c *v1beta1.CronJob) bool {
+	cronJob := e.Resources.GetCronJob(func(c *batchv1.CronJob) bool {
 		return c.Name == e.Integration.Name
 	})
 	if cronJob != nil {
diff --git a/pkg/util/kubernetes/collection.go b/pkg/util/kubernetes/collection.go
index 54e344905..f68b407b6 100644
--- a/pkg/util/kubernetes/collection.go
+++ b/pkg/util/kubernetes/collection.go
@@ -19,7 +19,7 @@ package kubernetes
 
 import (
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -268,9 +268,9 @@ func (c *Collection) GetRoute(filter func(*routev1.Route) bool) *routev1.Route {
 }
 
 // GetCronJob returns a CronJob that matches the given function.
-func (c *Collection) GetCronJob(filter func(job *v1beta1.CronJob) bool) *v1beta1.CronJob {
-	var retValue *v1beta1.CronJob
-	c.VisitCronJob(func(re *v1beta1.CronJob) {
+func (c *Collection) GetCronJob(filter func(job *batchv1.CronJob) bool) *batchv1.CronJob {
+	var retValue *batchv1.CronJob
+	c.VisitCronJob(func(re *batchv1.CronJob) {
 		if filter(re) {
 			retValue = re
 		}
@@ -279,18 +279,18 @@ func (c *Collection) GetCronJob(filter func(job *v1beta1.CronJob) bool) *v1beta1
 }
 
 // VisitCronJob executes the visitor function on all CronJob resources.
-func (c *Collection) VisitCronJob(visitor func(*v1beta1.CronJob)) {
+func (c *Collection) VisitCronJob(visitor func(*batchv1.CronJob)) {
 	c.Visit(func(res runtime.Object) {
-		if conv, ok := res.(*v1beta1.CronJob); ok {
+		if conv, ok := res.(*batchv1.CronJob); ok {
 			visitor(conv)
 		}
 	})
 }
 
 // VisitCronJobE executes the visitor function on all CronJob resources.
-func (c *Collection) VisitCronJobE(visitor func(*v1beta1.CronJob) error) error {
+func (c *Collection) VisitCronJobE(visitor func(*batchv1.CronJob) error) error {
 	return c.VisitE(func(res runtime.Object) error {
-		if conv, ok := res.(*v1beta1.CronJob); ok {
+		if conv, ok := res.(*batchv1.CronJob); ok {
 			return visitor(conv)
 		}
 
@@ -373,7 +373,7 @@ func (c *Collection) VisitContainer(visitor func(container *corev1.Container)) {
 			visitor(cntref)
 		}
 	})
-	c.VisitCronJob(func(c *v1beta1.CronJob) {
+	c.VisitCronJob(func(c *batchv1.CronJob) {
 		for idx := range c.Spec.JobTemplate.Spec.Template.Spec.Containers {
 			cntref := &c.Spec.JobTemplate.Spec.Template.Spec.Containers[idx]
 			visitor(cntref)
@@ -395,7 +395,7 @@ func (c *Collection) GetController(filter func(object ctrl.Object) bool) ctrl.Ob
 	if svc != nil {
 		return svc
 	}
-	cj := c.GetCronJob(func(job *v1beta1.CronJob) bool {
+	cj := c.GetCronJob(func(job *batchv1.CronJob) bool {
 		return filter(job)
 	})
 	if cj != nil {
@@ -412,7 +412,7 @@ func (c *Collection) VisitPodSpec(visitor func(container *corev1.PodSpec)) {
 	c.VisitKnativeConfigurationSpec(func(cs *serving.ConfigurationSpec) {
 		visitor(&cs.Template.Spec.PodSpec)
 	})
-	c.VisitCronJob(func(d *v1beta1.CronJob) {
+	c.VisitCronJob(func(d *batchv1.CronJob) {
 		visitor(&d.Spec.JobTemplate.Spec.Template.Spec)
 	})
 }
@@ -425,7 +425,7 @@ func (c *Collection) VisitPodTemplateMeta(visitor func(meta *metav1.ObjectMeta))
 	c.VisitKnativeConfigurationSpec(func(cs *serving.ConfigurationSpec) {
 		visitor(&cs.Template.ObjectMeta)
 	})
-	c.VisitCronJob(func(d *v1beta1.CronJob) {
+	c.VisitCronJob(func(d *batchv1.CronJob) {
 		visitor(&d.Spec.JobTemplate.Spec.Template.ObjectMeta)
 	})
 }
diff --git a/script/Makefile b/script/Makefile
index 7ac662583..434997c74 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -530,11 +530,7 @@ bundle: set-version generate-crd $(BUNDLE_CAMEL_APIS) kustomize operator-sdk pre
 			-q --overwrite --version $(OPERATOR_VERSION) \
 			--kustomize-dir config/manifests $(BUNDLE_METADATA_OPTS)
 	@# Move the dockerfile into the bundle directory
-ifeq ($(shell uname -s 2>/dev/null || echo Unknown),Darwin)
-	@mv bundle.Dockerfile bundle/Dockerfile && sed -i '' 's/bundle\///g' bundle/Dockerfile
-else
 	@mv bundle.Dockerfile bundle/Dockerfile && sed -i 's/bundle\///g' bundle/Dockerfile
-endif
 	@# Adds the licence headers to the csv file
 	./script/add_license.sh bundle/manifests ./script/headers/yaml.txt
 	$(OPERATOR_SDK) bundle validate ./bundle
diff --git a/script/add_createdAt.sh b/script/add_createdAt.sh
index 1dd1ad86c..8029d508c 100755
--- a/script/add_createdAt.sh
+++ b/script/add_createdAt.sh
@@ -35,11 +35,6 @@ created=$(date -u +%FT%TZ)
 
 set +e
 for file in `find "$dir" -type f`; do
-  if [[ "$OSTYPE" == "linux-gnu"* ]]; then
-    sed -i "s/createdAt: .*/createdAt: ${created}/" "${file}"
-  elif [[ "$OSTYPE" == "darwin"* ]]; then
-    # Mac OSX
-    sed -i '' "s/createdAt: .*/createdAt: ${created}/" "${file}"
-  fi
+  sed -i "s/createdAt: .*/createdAt: ${created}/" "${file}"
 done
 set -e
diff --git a/script/gen_crd.sh b/script/gen_crd.sh
index 2bfb8c7ec..ad03de070 100755
--- a/script/gen_crd.sh
+++ b/script/gen_crd.sh
@@ -40,16 +40,9 @@ deploy_crd_file() {
   # Post-process source
   cat ./script/headers/yaml.txt > "$source"
   echo "" >> "$source"
-  if [[ "$OSTYPE" == "linux-gnu"* ]]; then
-    cat "${source}.orig" | sed -n '/^---/,/^status/p;/^status/q' \
-      | sed '1d;$d' \
-      | sed '/creationTimestamp:/a\  labels:\n    app: camel-k' >> "$source"
-  elif [[ "$OSTYPE" == "darwin"* ]]; then
-    # Mac OSX
-    cat "${source}.orig" | sed -n '/^---/,/^status/p;/^status/q' \
-      | sed '1d;$d' \
-      | sed -e $'/^  creationTimestamp:/a\\\n  labels:\\\n    app: camel-k' >> "$source"
-  fi
+  cat "${source}.orig" | sed -n '/^---/,/^status/p;/^status/q' \
+    | sed '1d;$d' \
+    | sed '/creationTimestamp:/a\  labels:\n    app: camel-k' >> "$source"
 
   for dest in "${@:2}"; do
     cp "$source" "$dest"
diff --git a/script/set_go_modules_version.sh b/script/set_go_modules_version.sh
index 091f8533a..d67ae5d59 100755
--- a/script/set_go_modules_version.sh
+++ b/script/set_go_modules_version.sh
@@ -30,19 +30,9 @@ api_rule="s/github.com\/apache\/camel-k\/pkg\/apis\/camel [A-Za-z0-9\.\-]+.*$/gi
 client_rule="s/github.com\/apache\/camel-k\/pkg\/client\/camel [A-Za-z0-9\.\-]+.*$/github.com\/apache\/camel-k\/pkg\/client\/camel $target_tag/"
 kr_rule="s/github.com\/apache\/camel-k\/pkg\/kamelet\/repository [A-Za-z0-9\.\-]+.*$/github.com\/apache\/camel-k\/pkg\/kamelet\/repository $target_tag/"
 
-if [[ "$OSTYPE" == "linux-gnu"* ]]; then
-  sed -i -r "$api_rule"    $location/../go.mod
-  sed -i -r "$client_rule" $location/../go.mod
-  sed -i -r "$kr_rule"     $location/../go.mod
-  sed -i -r "$api_rule"    $location/../pkg/client/camel/go.mod
-  sed -i -r "$api_rule"    $location/../pkg/kamelet/repository/go.mod
-  sed -i -r "$client_rule" $location/../pkg/kamelet/repository/go.mod
-elif [[ "$OSTYPE" == "darwin"* ]]; then
-  # Mac OSX
-  sed -i '' -E "$api_rule"    $location/../go.mod
-  sed -i '' -E "$client_rule" $location/../go.mod
-  sed -i '' -E "$kr_rule"     $location/../go.mod
-  sed -i '' -E "$api_rule"    $location/../pkg/client/camel/go.mod
-  sed -i '' -E "$api_rule"    $location/../pkg/kamelet/repository/go.mod
-  sed -i '' -E "$client_rule" $location/../pkg/kamelet/repository/go.mod
-fi
+sed -i -r "$api_rule"    $location/../go.mod
+sed -i -r "$client_rule" $location/../go.mod
+sed -i -r "$kr_rule"     $location/../go.mod
+sed -i -r "$api_rule"    $location/../pkg/client/camel/go.mod
+sed -i -r "$api_rule"    $location/../pkg/kamelet/repository/go.mod
+sed -i -r "$client_rule" $location/../pkg/kamelet/repository/go.mod
diff --git a/script/set_version.sh b/script/set_version.sh
index 0d6dd1183..d47714d9d 100755
--- a/script/set_version.sh
+++ b/script/set_version.sh
@@ -30,34 +30,17 @@ k8s_version_label="app.kubernetes.io\/version"
 
 for f in $(find $location/../config/manager -type f -name "*.yaml");
 do
-  if [[ "$OSTYPE" == "linux-gnu"* ]]; then
-    sed -i -r "s/image: .*/image: ${sanitized_image_name}:${version}/" $f
-    sed -i -r "s/${k8s_version_label}: .*/${k8s_version_label}: \""${version}"\"/" $f
-  elif [[ "$OSTYPE" == "darwin"* ]]; then
-    # Mac OSX
-    sed -i '' -E "s/image: .*/image: ${sanitized_image_name}:${version}/" $f
-    sed -i '' -E "s/${k8s_version_label}: .*/${k8s_version_label}: \""${version}"\"/" $f
-  fi
+  sed -i -r "s/image: .*/image: ${sanitized_image_name}:${version}/" $f
+  sed -i -r "s/${k8s_version_label}: .*/${k8s_version_label}: \""${version}"\"/" $f
 done
 
 for f in $(find $location/../config/manifests/bases -type f -name "*.yaml");
 do
-  if [[ "$OSTYPE" == "linux-gnu"* ]]; then
-    sed -i -r "s/containerImage: .*/containerImage: ${sanitized_image_name}:${version}/" $f
-  elif [[ "$OSTYPE" == "darwin"* ]]; then
-    # Mac OSX
-    sed -i '' -E "s/containerImage: .*/containerImage: ${sanitized_image_name}:${version}/" $f
-  fi
+  sed -i -r "s/containerImage: .*/containerImage: ${sanitized_image_name}:${version}/" $f
 done
 
 # Update helm chart
-if [[ "$OSTYPE" == "linux-gnu"* ]]; then
-  sed -i -r "s/image: .*/image: ${sanitized_image_name}:${version}/" $location/../helm/camel-k/values.yaml
-  sed -i -r "s/appVersion:\s([0-9]+[a-zA-Z0-9\-\.].*).*/appVersion: ${version}/" $location/../helm/camel-k/Chart.yaml
-elif [[ "$OSTYPE" == "darwin"* ]]; then
-  # Mac OSX
-  sed -i '' -E "s/docker.io\/apache\/camel-k:([0-9]+[a-zA-Z0-9\-\.].*).*/${sanitized_image_name}:${version}/" $location/../helm/camel-k/values.yaml
-  sed -i '' -E "s/appVersion:\s([0-9]+[a-zA-Z0-9\-\.].*).*/appVersion: ${version}/" $location/../helm/camel-k/Chart.yaml
-fi
+sed -i -r "s/image: .*/image: ${sanitized_image_name}:${version}/" $location/../helm/camel-k/values.yaml
+sed -i -r "s/appVersion:\s([0-9]+[a-zA-Z0-9\-\.].*).*/appVersion: ${version}/" $location/../helm/camel-k/Chart.yaml
 
 echo "Camel K version set to: $version and image name to: $image_name"


Test patch:
diff --git a/e2e/common/cli/install_test.go b/e2e/common/cli/install_test.go
index b52f6c772..dfcefa0f9 100644
--- a/e2e/common/cli/install_test.go
+++ b/e2e/common/cli/install_test.go
@@ -38,7 +38,7 @@ import (
 	"github.com/apache/camel-k/pkg/util/defaults"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/apache/camel-k/pkg/util/openshift"
-	console "github.com/openshift/api/console/v1"
+	consolev1 "github.com/openshift/api/console/v1"
 )
 
 func TestBasicInstallation(t *testing.T) {
@@ -97,11 +97,11 @@ func TestConsoleCliDownload(t *testing.T) {
 	ocp, err := openshift.IsOpenShift(TestClient())
 	assert.Nil(t, err)
 
-	ok, err := kubernetes.IsAPIResourceInstalled(TestClient(), "console.openshift.io/v1", reflect.TypeOf(console.ConsoleCLIDownload{}).Name())
+	ok, err := kubernetes.IsAPIResourceInstalled(TestClient(), "console.openshift.io/v1", reflect.TypeOf(consolev1.ConsoleCLIDownload{}).Name())
 	assert.Nil(t, err)
 
 	if !ocp || !ok {
-		t.Skip("This test requires ConsoleCliDownload object which is available on OpenShift 4 only.")
+		t.Skip("This test requires ConsoleCliDownload object which is available on OpenShift 4+ only.")
 		return
 	}
 
diff --git a/e2e/common/cron_test.go b/e2e/common/cron_test.go
index dc26197db..db5b64178 100644
--- a/e2e/common/cron_test.go
+++ b/e2e/common/cron_test.go
@@ -23,17 +23,29 @@ limitations under the License.
 package common
 
 import (
+	"reflect"
 	"testing"
 
 	. "github.com/onsi/gomega"
+	"github.com/stretchr/testify/assert"
 
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 
 	. "github.com/apache/camel-k/e2e/support"
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
 func TestRunCronExample(t *testing.T) {
+	ok, err := kubernetes.IsAPIResourceInstalled(TestClient(), batchv1.SchemeGroupVersion.String(), reflect.TypeOf(batchv1.CronJob{}).Name())
+	assert.Nil(t, err)
+
+	if !ok {
+		t.Skip("This test requires CronJob batch/v1 API installed.")
+		return
+	}
+
 	WithNewTestNamespace(t, func(ns string) {
 		Expect(Kamel("install", "-n", ns).Execute()).To(Succeed())
 
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index e1e87ec2c..3fdd06077 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -46,7 +46,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	coordination "k8s.io/api/coordination/v1"
 	corev1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
@@ -599,12 +599,12 @@ func RouteStatus(ns string, name string) func() string {
 	}
 }
 
-func IntegrationCronJob(ns string, name string) func() *v1beta1.CronJob {
-	return func() *v1beta1.CronJob {
-		lst := v1beta1.CronJobList{
+func IntegrationCronJob(ns string, name string) func() *batchv1.CronJob {
+	return func() *batchv1.CronJob {
+		lst := batchv1.CronJobList{
 			TypeMeta: metav1.TypeMeta{
 				Kind:       "CronJob",
-				APIVersion: v1beta1.SchemeGroupVersion.String(),
+				APIVersion: batchv1.SchemeGroupVersion.String(),
 			},
 		}
 		err := TestClient().List(TestContext, &lst,
diff --git a/pkg/trait/cron_test.go b/pkg/trait/cron_test.go
index d6eb49169..0f2612473 100644
--- a/pkg/trait/cron_test.go
+++ b/pkg/trait/cron_test.go
@@ -24,7 +24,7 @@ import (
 	passert "github.com/magiconair/properties/assert"
 	"github.com/stretchr/testify/assert"
 
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
+	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
@@ -428,7 +428,7 @@ func TestCronWithActiveDeadline(t *testing.T) {
 	assert.Nil(t, ct.Fallback)
 	assert.Contains(t, environment.Interceptors, "cron")
 
-	cronJob := environment.Resources.GetCronJob(func(job *batchv1beta1.CronJob) bool { return true })
+	cronJob := environment.Resources.GetCronJob(func(job *batchv1.CronJob) bool { return true })
 	assert.NotNil(t, cronJob)
 
 	assert.NotNil(t, cronJob.Spec.JobTemplate.Spec.ActiveDeadlineSeconds)
@@ -501,7 +501,7 @@ func TestCronWithBackoffLimit(t *testing.T) {
 	assert.Nil(t, ct.Fallback)
 	assert.Contains(t, environment.Interceptors, "cron")
 
-	cronJob := environment.Resources.GetCronJob(func(job *batchv1beta1.CronJob) bool { return true })
+	cronJob := environment.Resources.GetCronJob(func(job *batchv1.CronJob) bool { return true })
 	assert.NotNil(t, cronJob)
 
 	assert.NotNil(t, cronJob.Spec.JobTemplate.Spec.ActiveDeadlineSeconds)
diff --git a/pkg/trait/test_support.go b/pkg/trait/test_support.go
new file mode 100644
index 000000000..31d77adc6
--- /dev/null
+++ b/pkg/trait/test_support.go
@@ -0,0 +1,117 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package trait
+
+import (
+	serving "knative.dev/serving/pkg/apis/serving/v1"
+
+	appsv1 "k8s.io/api/apps/v1"
+	batchv1 "k8s.io/api/batch/v1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+)
+
+func createNominalDeploymentTraitTest() (*Environment, *appsv1.Deployment) {
+	deployment := &appsv1.Deployment{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "integration-name",
+		},
+		Spec: appsv1.DeploymentSpec{
+			Template: corev1.PodTemplateSpec{},
+		},
+	}
+
+	environment := &Environment{
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "integration-name",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+		},
+		Resources: kubernetes.NewCollection(deployment),
+	}
+
+	return environment, deployment
+}
+
+func createNominalMissingDeploymentTraitTest() *Environment {
+	environment := &Environment{
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "integration-name",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+		},
+		Resources: kubernetes.NewCollection(),
+	}
+
+	return environment
+}
+
+func createNominalKnativeServiceTraitTest() (*Environment, *serving.Service) {
+	knativeService := &serving.Service{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "integration-name",
+		},
+		Spec: serving.ServiceSpec{},
+	}
+
+	environment := &Environment{
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "integration-name",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+		},
+		Resources: kubernetes.NewCollection(knativeService),
+	}
+
+	return environment, knativeService
+}
+
+func createNominalCronJobTraitTest() (*Environment, *batchv1.CronJob) {
+	cronJob := &batchv1.CronJob{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "integration-name",
+		},
+		Spec: batchv1.CronJobSpec{},
+	}
+
+	environment := &Environment{
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "integration-name",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+		},
+		Resources: kubernetes.NewCollection(cronJob),
+	}
+
+	return environment, cronJob
+}
diff --git a/pkg/trait/trait_types_test.go b/pkg/trait/trait_types_test.go
index 2a68853ae..9d3509de9 100644
--- a/pkg/trait/trait_types_test.go
+++ b/pkg/trait/trait_types_test.go
@@ -21,15 +21,8 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	serving "knative.dev/serving/pkg/apis/serving/v1"
-
-	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/batch/v1beta1"
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
-	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
 func TestMultilinePropertiesHandled(t *testing.T) {
@@ -45,89 +38,79 @@ func TestMultilinePropertiesHandled(t *testing.T) {
 	assert.Equal(t, "prop = multi\\nline\n", cm.Data["application.properties"])
 }
 
-func createNominalDeploymentTraitTest() (*Environment, *appsv1.Deployment) {
-	deployment := &appsv1.Deployment{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "integration-name",
-		},
-		Spec: appsv1.DeploymentSpec{
-			Template: corev1.PodTemplateSpec{},
-		},
-	}
-
-	environment := &Environment{
+func TestCollectConfigurationValues(t *testing.T) {
+	e := Environment{
 		Integration: &v1.Integration{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "integration-name",
-			},
-			Status: v1.IntegrationStatus{
-				Phase: v1.IntegrationPhaseDeploying,
+			Spec: v1.IntegrationSpec{
+				Configuration: []v1.ConfigurationSpec{
+					{Type: "configmap", Value: "my-cm-integration"},
+					{Type: "env", Value: "my-env-integration"},
+				},
 			},
 		},
-		Resources: kubernetes.NewCollection(deployment),
-	}
-
-	return environment, deployment
-}
-
-func createNominalMissingDeploymentTraitTest() *Environment {
-	environment := &Environment{
-		Integration: &v1.Integration{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "integration-name",
+		IntegrationKit: &v1.IntegrationKit{
+			Spec: v1.IntegrationKitSpec{
+				Configuration: []v1.ConfigurationSpec{
+					{Type: "configmap", Value: "my-cm-kit"},
+					{Type: "property", Value: "my-p-kit"},
+				},
 			},
-			Status: v1.IntegrationStatus{
-				Phase: v1.IntegrationPhaseDeploying,
+		},
+		Platform: &v1.IntegrationPlatform{
+			Spec: v1.IntegrationPlatformSpec{
+				Configuration: []v1.ConfigurationSpec{
+					{Type: "configmap", Value: "my-cm-platform"},
+					{Type: "secret", Value: "my-secret-platform"},
+					{Type: "property", Value: "my-p-platform"},
+					{Type: "env", Value: "my-env-platform"},
+				},
 			},
 		},
-		Resources: kubernetes.NewCollection(),
 	}
+	e.Platform.ResyncStatusFullConfig()
 
-	return environment
+	assert.Contains(t, e.collectConfigurationValues("configmap"), "my-cm-integration")
+	assert.Contains(t, e.collectConfigurationValues("secret"), "my-secret-platform")
+	assert.Contains(t, e.collectConfigurationValues("property"), "my-p-kit")
+	assert.Contains(t, e.collectConfigurationValues("env"), "my-env-integration")
 }
 
-func createNominalKnativeServiceTraitTest() (*Environment, *serving.Service) {
-	knativeService := &serving.Service{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "integration-name",
-		},
-		Spec: serving.ServiceSpec{},
-	}
-
-	environment := &Environment{
+func TestCollectConfigurationPairs(t *testing.T) {
+	e := Environment{
 		Integration: &v1.Integration{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "integration-name",
-			},
-			Status: v1.IntegrationStatus{
-				Phase: v1.IntegrationPhaseDeploying,
+			Spec: v1.IntegrationSpec{
+				Configuration: []v1.ConfigurationSpec{
+					{Type: "property", Value: "p1=integration"},
+					{Type: "property", Value: "p4=integration"},
+				},
 			},
 		},
-		Resources: kubernetes.NewCollection(knativeService),
-	}
-
-	return environment, knativeService
-}
-
-func createNominalCronJobTraitTest() (*Environment, *v1beta1.CronJob) {
-	cronJob := &v1beta1.CronJob{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "integration-name",
-		},
-		Spec: v1beta1.CronJobSpec{},
-	}
-
-	environment := &Environment{
-		Integration: &v1.Integration{
-			ObjectMeta: metav1.ObjectMeta{
-				Name: "integration-name",
+		IntegrationKit: &v1.IntegrationKit{
+			Spec: v1.IntegrationKitSpec{
+				Configuration: []v1.ConfigurationSpec{
+					{Type: "property", Value: "p1=kit"},
+					{Type: "property", Value: "p2=kit"},
+				},
 			},
-			Status: v1.IntegrationStatus{
-				Phase: v1.IntegrationPhaseDeploying,
+		},
+		Platform: &v1.IntegrationPlatform{
+			Spec: v1.IntegrationPlatformSpec{
+				Configuration: []v1.ConfigurationSpec{
+					{Type: "property", Value: "p1=platform"},
+					{Type: "property", Value: "p2=platform"},
+					{Type: "property", Value: "p3=platform"},
+					{Type: "property", Value: "p4=platform"},
+				},
 			},
 		},
-		Resources: kubernetes.NewCollection(cronJob),
 	}
-
-	return environment, cronJob
+	e.Platform.ResyncStatusFullConfig()
+
+	pairs := e.collectConfigurationPairs("property")
+	assert.Equal(t, pairs, []variable{
+		{Name: "p1", Value: "integration"},
+		{Name: "p2", Value: "kit"},
+		{Name: "p3", Value: "platform"},
+		{Name: "p4", Value: "integration"},
+	})
 }
diff --git a/pkg/trait/util_test.go b/pkg/trait/util_test.go
index d1488ad41..da4cd9589 100644
--- a/pkg/trait/util_test.go
+++ b/pkg/trait/util_test.go
@@ -21,87 +21,8 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 )
 
-func TestCollectConfigurationValues(t *testing.T) {
-	e := Environment{
-		Integration: &v1.Integration{
-			Spec: v1.IntegrationSpec{
-				Configuration: []v1.ConfigurationSpec{
-					{Type: "configmap", Value: "my-cm-integration"},
-					{Type: "env", Value: "my-env-integration"},
-				},
-			},
-		},
-		IntegrationKit: &v1.IntegrationKit{
-			Spec: v1.IntegrationKitSpec{
-				Configuration: []v1.ConfigurationSpec{
-					{Type: "configmap", Value: "my-cm-kit"},
-					{Type: "property", Value: "my-p-kit"},
-				},
-			},
-		},
-		Platform: &v1.IntegrationPlatform{
-			Spec: v1.IntegrationPlatformSpec{
-				Configuration: []v1.ConfigurationSpec{
-					{Type: "configmap", Value: "my-cm-platform"},
-					{Type: "secret", Value: "my-secret-platform"},
-					{Type: "property", Value: "my-p-platform"},
-					{Type: "env", Value: "my-env-platform"},
-				},
-			},
-		},
-	}
-	e.Platform.ResyncStatusFullConfig()
-
-	assert.Contains(t, e.collectConfigurationValues("configmap"), "my-cm-integration")
-	assert.Contains(t, e.collectConfigurationValues("secret"), "my-secret-platform")
-	assert.Contains(t, e.collectConfigurationValues("property"), "my-p-kit")
-	assert.Contains(t, e.collectConfigurationValues("env"), "my-env-integration")
-}
-
-func TestCollectConfigurationPairs(t *testing.T) {
-	e := Environment{
-		Integration: &v1.Integration{
-			Spec: v1.IntegrationSpec{
-				Configuration: []v1.ConfigurationSpec{
-					{Type: "property", Value: "p1=integration"},
-					{Type: "property", Value: "p4=integration"},
-				},
-			},
-		},
-		IntegrationKit: &v1.IntegrationKit{
-			Spec: v1.IntegrationKitSpec{
-				Configuration: []v1.ConfigurationSpec{
-					{Type: "property", Value: "p1=kit"},
-					{Type: "property", Value: "p2=kit"},
-				},
-			},
-		},
-		Platform: &v1.IntegrationPlatform{
-			Spec: v1.IntegrationPlatformSpec{
-				Configuration: []v1.ConfigurationSpec{
-					{Type: "property", Value: "p1=platform"},
-					{Type: "property", Value: "p2=platform"},
-					{Type: "property", Value: "p3=platform"},
-					{Type: "property", Value: "p4=platform"},
-				},
-			},
-		},
-	}
-	e.Platform.ResyncStatusFullConfig()
-
-	pairs := e.collectConfigurationPairs("property")
-	assert.Equal(t, pairs, []variable{
-		{Name: "p1", Value: "integration"},
-		{Name: "p2", Value: "kit"},
-		{Name: "p3", Value: "platform"},
-		{Name: "p4", Value: "integration"},
-	})
-}
-
 func TestBoolPointerFunctions(t *testing.T) {
 	trueP := BoolP(true)
 	falseP := BoolP(false)