Repository: apache/camel-k
Pull request #2497 (2021-07-12 16:54:03)

#2358: Possible to skip configuring of registry when installing via cli
* install.go
 * Use of --skip-registry-setup switch will bypass all configuration in
   relation to the registry and leave a blank structure in the newly
   installed platform

* Includes tests

* Makefile
 * Makes the IMAGE_NAME and VERSION overrideable on the cli

<!-- Description -->




<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
NONE
```



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e743c8b3f..3ea36fc6b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 
 **Closed issues:**
 
+- \[CMD\] `kamel bind` empty error handler [\#2493](https://github.com/apache/camel-k/issues/2493)
 - ServiceBinding CR sometimes doesn't get created [\#2482](https://github.com/apache/camel-k/issues/2482)
 - V1.5.0 release without assets [\#2481](https://github.com/apache/camel-k/issues/2481)
 - Release 1.4.1 [\#2471](https://github.com/apache/camel-k/issues/2471)
@@ -14,6 +15,8 @@
 
 **Merged pull requests:**
 
+- fix\(cmd/bind\): nullable error-handler [\#2496](https://github.com/apache/camel-k/pull/2496) ([squakez](https://github.com/squakez))
+- doc: remove programmatic datasource example [\#2491](https://github.com/apache/camel-k/pull/2491) ([squakez](https://github.com/squakez))
 - chore\(sbo-trait\): Upgrade Service Binding Operator to v0.8.0 [\#2488](https://github.com/apache/camel-k/pull/2488) ([johnpoth](https://github.com/johnpoth))
 - Fix \#2482: ServiceBinding CR should tied to the IntegrationPhaseWaiti… [\#2483](https://github.com/apache/camel-k/pull/2483) ([johnpoth](https://github.com/johnpoth))
 - chore\(release\): prepare 1.5.0 release [\#2478](https://github.com/apache/camel-k/pull/2478) ([nicolaferraro](https://github.com/nicolaferraro))
diff --git a/examples/amqp/amqpConsume.java b/examples/amqp/AmqpConnectionBeanConsumer.java
similarity index 62%
rename from examples/amqp/amqpConsume.java
rename to examples/amqp/AmqpConnectionBeanConsumer.java
index a2323f994..e4b876da7 100644
--- a/examples/amqp/amqpConsume.java
+++ b/examples/amqp/AmqpConnectionBeanConsumer.java
@@ -15,25 +15,16 @@
  * limitations under the License.
  */
 
+// You can bundle your credentials as a secret properties file:
 //
-// To run this integrations use:
-//
-//     kamel run -e BROKER_URL=event-bus-amqp-0-svc.messaging.svc.cluster.local -d camel-amqp examples/amqpConsumer.java
-//
-import org.apache.camel.BindToRegistry;
-
-public class amqpConsume extends org.apache.camel.builder.RouteBuilder {
-
-    @BindToRegistry
-    public javax.jms.ConnectionFactory connectionFactory() {
-        return new org.apache.qpid.jms.JmsConnectionFactory("amqp://" + java.lang.System.getenv("BROKER_URL"));
-    }
+// kubectl create secret generic my-amqp --from-file=amqp.properties
+// 
+// kamel run AmqpConnectionBeanConsumer.java --dev --config secret:my-amqp
 
+public class AmqpConnectionBeanConsumer extends org.apache.camel.builder.RouteBuilder {
     @Override
     public void configure() throws Exception {
-
-        from("amqp:topic:example?exchangePattern=InOnly")
+        from("amqp:queue:example?exchangePattern=InOnly")
             .to("log:info");
-
     }
 }
diff --git a/examples/amqp/AMQPBindToRegistry.java b/examples/amqp/AmqpConnectionBeanProducer.java
similarity index 61%
rename from examples/amqp/AMQPBindToRegistry.java
rename to examples/amqp/AmqpConnectionBeanProducer.java
index 20e2b5b79..c76642658 100644
--- a/examples/amqp/AMQPBindToRegistry.java
+++ b/examples/amqp/AmqpConnectionBeanProducer.java
@@ -15,27 +15,18 @@
  * limitations under the License.
  */
 
+// You can bundle your credentials as a secret properties file:
 //
-// To run this integrations use:
-//
-//     kamel run -e BROKER_URL=event-bus-amqp-0-svc.messaging.svc.cluster.local -d camel-amqp examples/amqp-bind-to-registry.java
-//
-import org.apache.camel.BindToRegistry;
-
-public class AMQPBindToRegistry extends org.apache.camel.builder.RouteBuilder {
-
-    @BindToRegistry
-    public javax.jms.ConnectionFactory connectionFactory() {
-        return new org.apache.qpid.jms.JmsConnectionFactory("amqp://" + java.lang.System.getenv("BROKER_URL"));
-    }
+// kubectl create secret generic my-amqp --from-file=amqp.properties
+// 
+// kamel run AmqpConnectionBeanProducer.java --dev --config secret:my-amqp
 
+public class AmqpConnectionBeanProducer extends org.apache.camel.builder.RouteBuilder {
     @Override
     public void configure() throws Exception {
-
-        from("timer:js?period=1000")
+        from("timer:foo?period=1000")
             .setBody()
                 .simple("Hello Camel K")
-            .to("amqp:topic:example?exchangePattern=InOnly");
-
+            .to("amqp:queue:example?exchangePattern=InOnly")
     }
 }
diff --git a/examples/amqp/README.md b/examples/amqp/README.md
index 01759451b..a23983d83 100644
--- a/examples/amqp/README.md
+++ b/examples/amqp/README.md
@@ -1,3 +1,5 @@
 # AMQP Camel K examples
 
-Find useful examples about how to use AMQP in a Camel K integration.
\ No newline at end of file
+Find useful examples about how to use AMQP in a Camel K integration.
+
+You may find useful instructions [how to install a JMS/AMQP Broker on Kubernetes](./artemis/) for demo purposes.
\ No newline at end of file
diff --git a/examples/amqp/amqp.properties b/examples/amqp/amqp.properties
new file mode 100644
index 000000000..851b01477
--- /dev/null
+++ b/examples/amqp/amqp.properties
@@ -0,0 +1,4 @@
+quarkus.qpid-jms.url=amqp://my-amqp-service:5672
+# Optional
+# quarkus.qpid-jms.username=xxxx
+# quarkus.qpid-jms.password=xxxx
diff --git a/examples/amqp/artemis/README.md b/examples/amqp/artemis/README.md
new file mode 100644
index 000000000..15db404f3
--- /dev/null
+++ b/examples/amqp/artemis/README.md
@@ -0,0 +1,26 @@
+# How to deploy a simple JMS/AMQP Broker to Kubernetes cluster
+
+This is a very simple example to show how to create a JMS/AMQP broker. **Note**, this is not ready for any production purpose.
+
+## Create a Kubernetes Deployment
+
+You can [install ActiveMQ Artemis on Kubernetes](https://artemiscloud.io/blog/using_operator/) thanks to ArtemisCloud.io. It would be enough to execute step 1, 2 and 3 of the linked blog post.
+
+## Create an AMQP broker instance
+
+Once the operator is up and running, you can proceed by creating a basic install of a broker accepting `amqp` protocol:
+
+```
+kubectl apply -f artemis-amqp.yaml
+```
+
+## Expose the Broker via service
+
+We need to make the broker accessible from the `Integration`. Let's do that via a `Service`:
+
+```
+kubectl apply -f artemis-service.yaml
+
+```
+
+We're now ready to use the `Broker`.
diff --git a/examples/amqp/artemis/artemis-amqp.yaml b/examples/amqp/artemis/artemis-amqp.yaml
new file mode 100644
index 000000000..0695e5bdc
--- /dev/null
+++ b/examples/amqp/artemis/artemis-amqp.yaml
@@ -0,0 +1,14 @@
+apiVersion: broker.amq.io/v2alpha4
+kind: ActiveMQArtemis
+metadata:
+  name: my-amqp
+spec:
+  deploymentPlan:
+    size: 1
+    image: placeholder
+  acceptors:
+  - name: amqp
+    protocols: amqp,openwire
+    port: 5672
+    sslEnabled: false
+    
\ No newline at end of file
diff --git a/examples/amqp/artemis/artemis-service.yaml b/examples/amqp/artemis/artemis-service.yaml
new file mode 100644
index 000000000..0ba587845
--- /dev/null
+++ b/examples/amqp/artemis/artemis-service.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: my-amqp-service
+  labels:
+    ActiveMQArtemis: my-amqp
+    application: my-amqp-app
+spec:
+  ports:
+    - port: 5672
+      name: amqp
+    - port: 8161
+      name: http
+  selector:
+    ActiveMQArtemis: my-amqp
+    application: my-amqp-app
+  type: NodePort
+  
\ No newline at end of file
diff --git a/examples/databases/postgres-deploy/README.md b/examples/databases/postgres-deploy/README.md
index 0b095b43c..1c4a9ecdf 100644
--- a/examples/databases/postgres-deploy/README.md
+++ b/examples/databases/postgres-deploy/README.md
@@ -1,6 +1,6 @@
 # How to deploy a simple Postgres DB to Kubernetes cluster
 
-This is a very simple example to show how to create a Postgres database. **Note**, this is not ready for any production purposes.
+This is a very simple example to show how to create a Postgres database. **Note**, this is not ready for any production purpose.
 
 ## Create a Kubernetes Deployment
 ```
@@ -9,7 +9,7 @@ kubectl create -f postgres-storage.yaml
 kubectl create -f postgres-deployment.yaml
 kubectl create -f postgres-service.yaml
 ```
-## Thest the connection
+## Test the connection
 
 Connection credentials available in the _postgres-configmap.yaml_ descriptor.
 
diff --git a/examples/user-config/resource-secret-route.groovy b/examples/user-config/resource-secret-route.groovy
index c6dc92396..aab496b1f 100644
--- a/examples/user-config/resource-secret-route.groovy
+++ b/examples/user-config/resource-secret-route.groovy
@@ -23,5 +23,5 @@
 // kamel run --resource secret:my-sec resource-secret-route.groovy --dev
 //
 
-from('file:/etc/camel/my-sec/?fileName=my-secret-key&noop=true&idempotent=false')
+from('file:/etc/camel/resources/my-sec/?fileName=my-secret-key&noop=true&idempotent=false')
     .log('resource file content is: ${body}')
diff --git a/pkg/apis/camel/v1alpha1/kamelet_binding_types.go b/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
index cfe8779d1..4341c1c4b 100644
--- a/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
+++ b/pkg/apis/camel/v1alpha1/kamelet_binding_types.go
@@ -33,7 +33,7 @@ type KameletBindingSpec struct {
 	// Sink is the destination of the integration defined by this binding
 	Sink Endpoint `json:"sink,omitempty"`
 	// ErrorHandler is an optional handler called upon an error occuring in the integration
-	ErrorHandler ErrorHandlerSpec `json:"errorHandler,omitempty"`
+	ErrorHandler *ErrorHandlerSpec `json:"errorHandler,omitempty"`
 	// Steps contains an optional list of intermediate steps that are executed between the Source and the Sink
 	Steps []Endpoint `json:"steps,omitempty"`
 }
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index e690240ef..c0437a9e9 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -535,7 +535,11 @@ func (in *KameletBindingSpec) DeepCopyInto(out *KameletBindingSpec) {
 	}
 	in.Source.DeepCopyInto(&out.Source)
 	in.Sink.DeepCopyInto(&out.Sink)
-	in.ErrorHandler.DeepCopyInto(&out.ErrorHandler)
+	if in.ErrorHandler != nil {
+		in, out := &in.ErrorHandler, &out.ErrorHandler
+		*out = new(ErrorHandlerSpec)
+		(*in).DeepCopyInto(*out)
+	}
 	if in.Steps != nil {
 		in, out := &in.Steps, &out.Steps
 		*out = make([]Endpoint, len(*in))
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 26d3a1687..46c492b11 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -74,6 +74,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
 	cmd.Flags().String("cluster-type", "", "Set explicitly the cluster type to Kubernetes or OpenShift")
 	cmd.Flags().Bool("skip-operator-setup", false, "Do not install the operator in the namespace (in case there's a global one)")
 	cmd.Flags().Bool("skip-cluster-setup", false, "Skip the cluster-setup phase")
+	cmd.Flags().Bool("skip-registry-setup", false, "Skip the registry-setup phase (may negatively impact building of integrations)")
 	cmd.Flags().Bool("example", false, "Install example integration")
 	cmd.Flags().Bool("global", false, "Configure the operator to watch all namespaces. No integration platform is created. You can run integrations in a namespace by installing an integration platform: 'kamel install --skip-operator-setup -n my-namespace'")
 	cmd.Flags().Bool("force", false, "Force replacement of configuration resources when already present.")
@@ -152,6 +153,7 @@ type installCmdOptions struct {
 	ClusterSetupOnly        bool     `mapstructure:"cluster-setup"`
 	SkipOperatorSetup       bool     `mapstructure:"skip-operator-setup"`
 	SkipClusterSetup        bool     `mapstructure:"skip-cluster-setup"`
+	SkipRegistrySetup       bool     `mapstructure:"skip-registry-setup"`
 	ExampleSetup            bool     `mapstructure:"example"`
 	Global                  bool     `mapstructure:"global"`
 	KanikoBuildCache        bool     `mapstructure:"kaniko-build-cache"`
@@ -291,21 +293,26 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		}
 
 		generatedSecretName := ""
-		if o.registryAuth.IsSet() {
-			regData := o.registryAuth
-			regData.Registry = o.registry.Address
-			generatedSecretName, err = install.RegistrySecretOrCollect(o.Context, c, namespace, regData, collection, o.Force)
-			if err != nil {
-				return err
-			}
-		} else if o.RegistryAuthFile != "" {
-			generatedSecretName, err = install.RegistrySecretFromFileOrCollect(o.Context, c, namespace, o.RegistryAuthFile, collection, o.Force)
-			if err != nil {
-				return err
+
+		if !o.SkipRegistrySetup {
+			if o.registryAuth.IsSet() {
+				regData := o.registryAuth
+				regData.Registry = o.registry.Address
+				generatedSecretName, err = install.RegistrySecretOrCollect(o.Context, c, namespace, regData, collection, o.Force)
+				if err != nil {
+					return err
+				}
+			} else if o.RegistryAuthFile != "" {
+				generatedSecretName, err = install.RegistrySecretFromFileOrCollect(o.Context, c, namespace, o.RegistryAuthFile, collection, o.Force)
+				if err != nil {
+					return err
+				}
 			}
+		} else if o.SkipRegistrySetup {
+			fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K operator registry setup skipped")
 		}
 
-		platform, err := install.PlatformOrCollect(o.Context, c, o.ClusterType, namespace, o.registry, collection)
+		platform, err := install.PlatformOrCollect(o.Context, c, o.ClusterType, namespace, o.SkipRegistrySetup, o.registry, collection)
 		if err != nil {
 			return err
 		}
diff --git a/pkg/controller/kameletbinding/error_handler.go b/pkg/controller/kameletbinding/error_handler.go
index 5325324f0..4f7115624 100644
--- a/pkg/controller/kameletbinding/error_handler.go
+++ b/pkg/controller/kameletbinding/error_handler.go
@@ -27,9 +27,9 @@ import (
 	"github.com/pkg/errors"
 )
 
-func maybeErrorHandler(errHandlConf v1alpha1.ErrorHandlerSpec, bindingContext bindings.BindingContext) (*bindings.Binding, error) {
+func maybeErrorHandler(errHandlConf *v1alpha1.ErrorHandlerSpec, bindingContext bindings.BindingContext) (*bindings.Binding, error) {
 	var errorHandlerBinding *bindings.Binding
-	if errHandlConf.RawMessage != nil {
+	if errHandlConf != nil && &errHandlConf.RawMessage != nil {
 		errorHandlerSpec, err := parseErrorHandler(errHandlConf.RawMessage)
 		if err != nil {
 			return nil, errors.Wrap(err, "could not parse error handler")
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 54dc2dff5..513deeff1 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -410,7 +410,7 @@ func installServiceBindings(ctx context.Context, c client.Client, namespace stri
 
 // PlatformOrCollect --
 // nolint: lll
-func PlatformOrCollect(ctx context.Context, c client.Client, clusterType string, namespace string, registry v1.IntegrationPlatformRegistrySpec, collection *kubernetes.Collection) (*v1.IntegrationPlatform, error) {
+func PlatformOrCollect(ctx context.Context, c client.Client, clusterType string, namespace string, skipRegistrySetup bool, registry v1.IntegrationPlatformRegistrySpec, collection *kubernetes.Collection) (*v1.IntegrationPlatform, error) {
 	isOpenShift, err := isOpenShift(c, clusterType)
 	if err != nil {
 		return nil, err
@@ -421,7 +421,7 @@ func PlatformOrCollect(ctx context.Context, c client.Client, clusterType string,
 	}
 	pl := platformObject.(*v1.IntegrationPlatform)
 
-	if !isOpenShift {
+	if !isOpenShift && !skipRegistrySetup {
 		pl.Spec.Build.Registry = registry
 
 		// Kubernetes only (Minikube)
diff --git a/script/Makefile b/script/Makefile
index c50cb8255..d07d92266 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 VERSIONFILE := pkg/util/defaults/defaults.go
-VERSION := 1.5.0-SNAPSHOT
+VERSION ?= 1.5.0-SNAPSHOT
 OPERATOR_VERSION := $(subst -SNAPSHOT,,$(VERSION))
 LAST_RELEASED_VERSION := 1.4.1
 RUNTIME_VERSION := 1.8.0
@@ -23,7 +23,7 @@ KANIKO_VERSION := 0.17.1
 INSTALL_DEFAULT_KAMELETS := true
 BASE_IMAGE := adoptopenjdk/openjdk11:slim
 LOCAL_REPOSITORY := /tmp/artifacts/m2
-IMAGE_NAME := docker.io/apache/camel-k
+IMAGE_NAME ?= docker.io/apache/camel-k
 METADATA_IMAGE_NAME := $(IMAGE_NAME)-metadata
 RELEASE_GIT_REMOTE := upstream
 GIT_COMMIT := $(shell git rev-list -1 HEAD)


Test patch:
diff --git a/e2e/common/cli/install_test.go b/e2e/common/cli/install_test.go
index 34fd08e3f..8666ec01f 100644
--- a/e2e/common/cli/install_test.go
+++ b/e2e/common/cli/install_test.go
@@ -27,6 +27,7 @@ import (
 	. "github.com/onsi/gomega"
 
 	. "github.com/apache/camel-k/e2e/support"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 )
 
 func TestBasicInstallation(t *testing.T) {
@@ -60,3 +61,17 @@ func TestMavenRepositoryInstallation(t *testing.T) {
 		}).Should(ContainSubstring("https://my.repo.org/public/"))
 	})
 }
+
+/*
+ * Expert mode where user does not want a registry configured
+ * so the Platform will have an empty Registry structure
+ */
+func TestSkipRegistryInstallation(t *testing.T) {
+	WithNewTestNamespace(t, func(ns string) {
+		Expect(Kamel("install", "-n", ns, "--skip-registry-setup").Execute()).To(Succeed())
+		Eventually(Platform(ns)).ShouldNot(BeNil())
+		Eventually(func() v1.IntegrationPlatformRegistrySpec {
+			return Platform(ns)().Spec.Build.Registry
+		}, TestTimeoutMedium).Should(Equal(v1.IntegrationPlatformRegistrySpec{}))
+	})
+}
diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go
index c0d0ed202..de3561b4f 100644
--- a/pkg/cmd/install_test.go
+++ b/pkg/cmd/install_test.go
@@ -314,6 +314,13 @@ func TestInstallSkipOperatorSetupFlag(t *testing.T) {
 	assert.Equal(t, true, installCmdOptions.SkipOperatorSetup)
 }
 
+func TestInstallSkipRegistrySetupFlag(t *testing.T) {
+	installCmdOptions, rootCmd, _ := initializeInstallCmdOptions(t)
+	_, err := test.ExecuteCommand(rootCmd, cmdInstall, "--skip-registry-setup")
+	assert.Nil(t, err)
+	assert.Equal(t, true, installCmdOptions.SkipRegistrySetup)
+}
+
 func TestInstallTraitProfileFlag(t *testing.T) {
 	installCmdOptions, rootCmd, _ := initializeInstallCmdOptions(t)
 	_, err := test.ExecuteCommand(rootCmd, cmdInstall, "--trait-profile", "someString")
diff --git a/pkg/trait/pull_secret_test.go b/pkg/trait/pull_secret_test.go
index a1499e014..9efe192a1 100644
--- a/pkg/trait/pull_secret_test.go
+++ b/pkg/trait/pull_secret_test.go
@@ -18,6 +18,7 @@ limitations under the License.
 package trait
 
 import (
+	"strings"
 	"testing"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
@@ -29,21 +30,7 @@ import (
 )
 
 func TestPullSecret(t *testing.T) {
-	e := &Environment{}
-	e.Integration = &v1.Integration{
-		Status: v1.IntegrationStatus{
-			Phase: v1.IntegrationPhaseDeploying,
-		},
-	}
-
-	deployment := appsv1.Deployment{
-		Spec: appsv1.DeploymentSpec{
-			Template: corev1.PodTemplateSpec{
-				Spec: corev1.PodSpec{},
-			},
-		},
-	}
-	e.Resources = kubernetes.NewCollection(&deployment)
+	e, deployment := getEnvironmentAndDeployment()
 
 	trait := newPullSecretTrait().(*pullSecretTrait)
 	trait.SecretName = "xxxy"
@@ -57,13 +44,56 @@ func TestPullSecret(t *testing.T) {
 }
 
 func TestPullSecretDoesNothingWhenNotSetOnPlatform(t *testing.T) {
+	e, _ := getEnvironmentAndDeployment()
+	e.Platform = &v1.IntegrationPlatform{}
+
+	trait := newPullSecretTrait()
+	enabled, err := trait.Configure(e)
+	assert.Nil(t, err)
+	assert.False(t, enabled)
+}
+
+func TestPullSecretAuto(t *testing.T) {
+	e, _ := getEnvironmentAndDeployment()
+
+	trait := newPullSecretTrait().(*pullSecretTrait)
+	trait.Auto = newFalse()
+	enabled, err := trait.Configure(e)
+	assert.Nil(t, err)
+	assert.False(t, enabled)
+}
+
+func TestPullSecretImagePullerDelegation(t *testing.T) {
+	e, _ := getEnvironmentAndDeployment()
+
+	trait := newPullSecretTrait().(*pullSecretTrait)
+	trait.Auto = newFalse()
+	trait.ImagePullerDelegation = newTrue()
+	enabled, err := trait.Configure(e)
+	assert.Nil(t, err)
+	assert.True(t, enabled)
+	assert.True(t, *trait.ImagePullerDelegation)
+
+	err = trait.Apply(e)
+	assert.Nil(t, err)
+
+	found := false
+	for _, item := range e.Resources.Items() {
+		found = strings.HasPrefix(item.GetName(), "camel-k-puller")
+		if found {
+			break
+		}
+	}
+	assert.True(t, found)
+}
+
+func getEnvironmentAndDeployment() (*Environment, *appsv1.Deployment) {
 	e := &Environment{}
 	e.Integration = &v1.Integration{
 		Status: v1.IntegrationStatus{
 			Phase: v1.IntegrationPhaseDeploying,
 		},
 	}
-	e.Platform = &v1.IntegrationPlatform{}
 
 	deployment := appsv1.Deployment{
 		Spec: appsv1.DeploymentSpec{
@@ -74,8 +104,15 @@ func TestPullSecretDoesNothingWhenNotSetOnPlatform(t *testing.T) {
 	}
 	e.Resources = kubernetes.NewCollection(&deployment)
 
-	trait := newPullSecretTrait()
-	enabled, err := trait.Configure(e)
-	assert.Nil(t, err)
-	assert.False(t, enabled)
+	return e, &deployment
+}
+
+func newFalse() *bool {
+	b := false
+	return &b
+}
+
+func newTrue() *bool {
+	b := true
+	return &b
 }