You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2022/01/31 08:58:12 UTC

[camel-k] 01/40: Refactors e2e testing to allow for platform delegation

This is an automated email from the ASF dual-hosted git repository.

astefanutti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 1638fc1d4fe5ec7738c714d359b42cb5ecc2f3b1
Author: phantomjinx <p....@phantomjinx.co.uk>
AuthorDate: Fri Jan 14 14:22:49 2022 +0000

    Refactors e2e testing to allow for platform delegation
    
    * Allows a repo to select underlying platform, ie. kind, ocp3 or
      custom, where latter is guided by secrets located in the private repo
    
    * Refactors duplicate steps into actions so pairing down the content of the
      workflow
    
    * Utilises inputs and outputs to actions for action-action and action-workflow
      comms
---
 .github/.env                                       |   1 +
 .github/actions/action-dotenv-to-setenv            |   1 +
 .github/actions/conditional                        |   1 +
 .github/actions/kamel-build-bundle/action.yaml     |  88 ++++++++
 .github/actions/kamel-build/action.yml             |  77 +++++++
 .../actions/kamel-config-cluster-custom/action.yml | 131 +++++++++++
 .../actions/kamel-config-cluster-kind/action.yml   |  48 ++++
 .../kamel-config-cluster-ocp3/action.yml}          | 118 +++-------
 .github/actions/kamel-config-cluster/action.yaml   | 180 +++++++++++++++
 .../actions/kamel-install-cluster-setup/action.yml |  54 +++++
 .github/actions/kamel-install-knative/action.yml   |  63 ++++++
 .github/actions/kamel-prepare-env/action.yml       | 105 +++++++++
 .github/workflows/build.yml                        |  18 +-
 .github/workflows/builder.yml                      |  87 +++----
 .github/workflows/knative.yml                      | 249 ++++++---------------
 .github/workflows/kubernetes.yml                   |  85 +++----
 .github/workflows/local.yml                        |  35 +--
 .github/workflows/openshift.yml                    | 198 ++--------------
 .github/workflows/upgrade.yml                      | 125 ++++-------
 .gitmodules                                        |   8 +
 script/Makefile                                    |   3 +
 21 files changed, 996 insertions(+), 679 deletions(-)

diff --git a/.github/.env b/.github/.env
new file mode 100644
index 0000000..cd5940c
--- /dev/null
+++ b/.github/.env
@@ -0,0 +1 @@
+TEST_PLATFORM_CLUSTER=kind
diff --git a/.github/actions/action-dotenv-to-setenv b/.github/actions/action-dotenv-to-setenv
new file mode 160000
index 0000000..a6380f4
--- /dev/null
+++ b/.github/actions/action-dotenv-to-setenv
@@ -0,0 +1 @@
+Subproject commit a6380f4d905f42adb7c065db63e6d66d75b971ad
diff --git a/.github/actions/conditional b/.github/actions/conditional
new file mode 160000
index 0000000..3fce4b7
--- /dev/null
+++ b/.github/actions/conditional
@@ -0,0 +1 @@
+Subproject commit 3fce4b7a3171a839b482306f9fd3aba0c2112a24
diff --git a/.github/actions/kamel-build-bundle/action.yaml b/.github/actions/kamel-build-bundle/action.yaml
new file mode 100644
index 0000000..19a3c95
--- /dev/null
+++ b/.github/actions/kamel-build-bundle/action.yaml
@@ -0,0 +1,88 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-build-bundle
+description: 'Builds kamel operator metadata bundle'
+
+inputs:
+  image-registry:
+    description: 'Location of image registry to push bundle'
+    required: true
+  local-image-name:
+    description: 'Reference of the camel-k image'
+    required: true
+  local-image-version:
+    description: "Reference of the camel-k image version"
+    required: true
+
+runs:
+  using: "composite"
+  steps:
+
+    - id: build-bundle-image
+      name: Build Operator bundle
+      shell: bash
+      run: |
+        echo "Build Operator bundle"
+        if ! command -v kustomize &> /dev/null
+        then
+          echo "kustomize could not be found. Has it not been installed?"
+          exit 1
+        fi
+
+        # replace image
+        $(cd config/manifests && kustomize edit set image "docker.io/apache/camel-k=${{ inputs.local-image-name }}:${{ inputs.local-image-version }}")
+
+        # Patch CSV with the 'replaces' field to define the upgrade graph
+        # Use sed as the manifest/bases file is not included in the kustomize config
+        BASE_VERSION=$(echo ${{ inputs.local-image-version }} | grep -Po "\d.\d.\d")
+        sed -i "/  version: ${BASE_VERSION}/a \ \ replaces: camel-k-operator.v$(make get-last-released-version)" config/manifests/bases/camel-k.clusterserviceversion.yaml
+
+        export CUSTOM_IMAGE=${{ inputs.local-image-name }}
+        export LOCAL_IMAGE_BUNDLE=${{ inputs.image-registry }}/apache/camel-k-bundle:${{ inputs.local-image-version }}
+        export PREV_XY_CHANNEL=stable-$(make get-last-released-version | grep -Po "\d.\d")
+        echo "PREV_XY_CHANNEL=${PREV_XY_CHANNEL}" >> $GITHUB_ENV
+        export NEW_XY_CHANNEL=stable-$(make get-version | grep -Po "\d.\d")
+        echo "NEW_XY_CHANNEL=${NEW_XY_CHANNEL}" >> $GITHUB_ENV
+        make bundle-build BUNDLE_IMAGE_NAME=${LOCAL_IMAGE_BUNDLE} DEFAULT_CHANNEL="${NEW_XY_CHANNEL}" CHANNELS="${NEW_XY_CHANNEL}"
+        docker push ${LOCAL_IMAGE_BUNDLE}
+
+        echo "::set-output name=local-image-bundle::$(echo ${LOCAL_IMAGE_BUNDLE})"
+
+    - id: build-index-image
+      name: Create New Index Image
+      shell: bash
+      run: |
+        export LOCAL_IIB=${{ inputs.image-registry }}/apache/camel-k-iib:${{ inputs.local-image-version }}
+        if ! command -v opm &> /dev/null
+        then
+          echo "opm could not be found. Has it not been installed?"
+          exit 1
+        fi
+
+        opm index add --bundles ${{ steps.build-bundle-image.outputs.local-image-bundle }} -c docker --from-index quay.io/operatorhubio/catalog:latest --tag ${LOCAL_IIB} --skip-tls
+        docker push ${LOCAL_IIB}
+
+        echo "::set-output name=local-image-bundle-index::$(echo ${LOCAL_IIB})"
+
+outputs:
+  local-image-bundle:
+    description: "Reference of the camel-k metadata bundle image"
+    value: ${{ steps.build-bundle-image.outputs.local-image-bundle }}
+  local-image-bundle-index:
+    description: "Reference of the camel-k metadata bundle index image"
+    value: ${{ steps.build-index-image.outputs.local-image-bundle-index }}
diff --git a/.github/actions/kamel-build/action.yml b/.github/actions/kamel-build/action.yml
new file mode 100644
index 0000000..7414da1
--- /dev/null
+++ b/.github/actions/kamel-build/action.yml
@@ -0,0 +1,77 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-build
+description: 'Builds kamel operator binary'
+
+inputs:
+  image-registry:
+    description: 'Location of image registry if required'
+    required: false
+  make-rules:
+    description: 'Override the default make rules'
+    required: false
+  install-kamel-binary:
+    description: 'Install the kamel binary onto the path'
+    required: false
+    default: true
+
+runs:
+  using: "composite"
+  steps:
+    - id: build-operator
+      name: Build Kamel Operator
+      shell: bash
+      run: |
+        echo "Build Kamel from source"
+
+        if [ -n "${{ inputs.image-registry }}" ]; then
+          export CUSTOM_IMAGE=${{ inputs.image-registry }}/apache/camel-k
+          echo "::set-output name=custom-img::$(echo ${CUSTOM_IMAGE})"
+        fi
+
+        RULES="PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images"
+        if [ -n "${{ inputs.make-rules }}" ]; then
+          RULES="${{ inputs.make-rules }}"
+        fi
+
+        if [ -n "${{ inputs.image-registry }}" ]; then
+          RULES="${RULES} images-push"
+        fi
+
+        make ${RULES}
+
+        if [ "${{ inputs.install-kamel-binary }}" == "true" ]; then
+          echo "Moving kamel binary to /usr/local/bin"
+          sudo mv ./kamel /usr/local/bin
+          echo "Kamel version installed: $(kamel version)"
+        fi
+
+        echo "::set-output name=local-img-name::$(make get-image)"
+        echo "::set-output name=local-img-version::$(make get-version)"
+
+
+outputs:
+  custom-image:
+    description: "Reference of the camel-k image"
+    value: ${{ steps.build-operator.outputs.custom-img }}
+  local-image-name:
+    description: "Reference of the camel-k image"
+    value: ${{ steps.build-operator.outputs.local-img-name }}
+  local-image-version:
+    description: "Reference of the camel-k image version"
+    value: ${{ steps.build-operator.outputs.local-img-version }}
diff --git a/.github/actions/kamel-config-cluster-custom/action.yml b/.github/actions/kamel-config-cluster-custom/action.yml
new file mode 100644
index 0000000..46bbe5e
--- /dev/null
+++ b/.github/actions/kamel-config-cluster-custom/action.yml
@@ -0,0 +1,131 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-config-cluster-custom
+description: 'Provides configuration for acessing a custom kubernetes cluster'
+
+runs:
+  using: "composite"
+  steps:
+    - id: connect-cluster
+      name: Connect to cluster
+      shell: bash
+      run: |
+        if [ -z "${KUBE_CONFIG_DATA}" ]; then
+          echo "Error: KUBE_CONFIG_DATA secret cannot be found"
+          exit 1
+        fi
+
+        if [ -z "${KUBE_ADMIN_USER_CTX}" ]; then
+          echo "Error: KUBE_ADMIN_USER_CTX secret cannot be found"
+          exit 1
+        fi
+
+        if [ -z "${KUBE_USER_CTX}" ]; then
+          echo "Error: KUBE_USER_CTX secret cannot be found"
+          exit 1
+        fi
+
+        # IMAGE_REGISTRY & IMAGE_REGISTRY_INSECURE are optional
+
+        # Copy the kube config to the correct location for kubectl
+        mkdir -p $HOME/.kube
+        echo -n "${KUBE_CONFIG_DATA}" | base64 -d > ${HOME}/.kube/config
+        if [ ! -f ${HOME}/.kube/config ]; then
+          echo "Error: kube config file not created correctly"
+          exit 1
+        fi
+
+        set -e
+        kubectl config use-context "${KUBE_ADMIN_USER_CTX}"
+        if [ $? != 0 ]; then
+          echo "Error: Failed to select kube admin context. Is the config and context correct?"
+          exit 1
+        fi
+        set +e
+
+        # Export the context variables
+        echo "KUBE_ADMIN_USER_CTX=${KUBE_ADMIN_USER_CTX}" >> $GITHUB_ENV
+        echo "KUBE_USER_CTX=${KUBE_USER_CTX}" >> $GITHUB_ENV
+        echo "IMAGE_REGISTRY=${IMAGE_REGISTRY}" >> $GITHUB_ENV
+        echo "IMAGE_REGISTRY_INSECURE=${IMAGE_REGISTRY_INSECURE}" >> $GITHUB_ENV
+
+    - id: info
+      name: Info
+      shell: bash
+      run: |
+        kubectl describe nodes
+
+    - id: configure-developer-user
+      name: Configure Developer User
+      shell: bash
+      run: |
+        # Aggregate pod eviction permission to the default admin role
+        cat <<EOF | oc apply -f -
+        kind: ClusterRole
+        apiVersion: rbac.authorization.k8s.io/v1
+        metadata:
+          name: camel-k-test:eviction
+          labels:
+            rbac.authorization.k8s.io/aggregate-to-admin: "true"
+        rules:
+        - apiGroups: [""]
+          resources: ["pods/eviction"]
+          verbs: ["create"]
+        EOF
+
+        # Grant nodes permission to the default developer user
+        cat <<EOF | oc apply -f -
+        kind: ClusterRole
+        apiVersion: rbac.authorization.k8s.io/v1
+        metadata:
+          name: camel-k-test:nodes
+        rules:
+        - apiGroups: [""]
+          resources: ["nodes"]
+          verbs: ["get","list"]
+        EOF
+        cat <<EOF | oc apply -f -
+        kind: ClusterRoleBinding
+        apiVersion: rbac.authorization.k8s.io/v1
+        metadata:
+          name: camel-k-test:nodes
+        subjects:
+        - kind: User
+          name: developer
+        roleRef:
+          kind: ClusterRole
+          name: camel-k-test:nodes
+          apiGroup: rbac.authorization.k8s.io
+        EOF
+
+        # Aggregate finalizers permission to the default admin role
+        cat <<EOF | oc apply -f -
+        kind: ClusterRole
+        apiVersion: rbac.authorization.k8s.io/v1
+        metadata:
+          name: camel-k-test:finalizers
+          labels:
+            rbac.authorization.k8s.io/aggregate-to-admin: "true"
+        rules:
+        - apiGroups: ["camel.apache.org"]
+          resources: ["*/finalizers"]
+          verbs: ["update"]
+        EOF
+
+        # Set the context to the user
+        kubectl config use-context "${{ env.KUBE_USER_CTX }}"
diff --git a/.github/actions/kamel-config-cluster-kind/action.yml b/.github/actions/kamel-config-cluster-kind/action.yml
new file mode 100644
index 0000000..48b02bd
--- /dev/null
+++ b/.github/actions/kamel-config-cluster-kind/action.yml
@@ -0,0 +1,48 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-config-cluster-kind
+description: 'Provides configuration for making available kubernetes cluster on kind'
+
+runs:
+  using: "composite"
+  steps:
+    - id: install-cluster
+      name: Install Cluster
+      uses: container-tools/kind-action@v1
+      with:
+        version: v0.11.0
+        node_image: kindest/node:v1.21.1@sha256:fae9a58f17f18f06aeac9772ca8b5ac680ebbed985e266f711d936e91d113bad
+    - id: info
+      name: Info
+      shell: bash
+      run: |
+        kubectl cluster-info
+        kubectl describe nodes
+
+    - id: extract-config
+      shell: bash
+      run: |
+        echo "IMAGE_REGISTRY=${{ env.KIND_REGISTRY }}" >> $GITHUB_ENV
+        echo "IMAGE_REGISTRY_INSECURE=true" >> $GITHUB_ENV
+
+        #
+        # Export the context used for admin and user
+        # Since kind has no rbac switched on then these can be the same
+        #
+        echo "KUBE_ADMIN_USER_CTX=$(kubectl config current-context)" >> $GITHUB_ENV
+        echo "KUBE_USER_CTX=$(kubectl config current-context)" >> $GITHUB_ENV
diff --git a/.github/workflows/openshift.yml b/.github/actions/kamel-config-cluster-ocp3/action.yml
similarity index 71%
copy from .github/workflows/openshift.yml
copy to .github/actions/kamel-config-cluster-ocp3/action.yml
index c7cd72d..8d6bfb9 100644
--- a/.github/workflows/openshift.yml
+++ b/.github/actions/kamel-config-cluster-ocp3/action.yml
@@ -15,73 +15,14 @@
 # limitations under the License.
 # ---------------------------------------------------------------------------
 
-name: openshift
-
-on:
-  pull_request:
-    branches:
-      - main
-      - "release-*"
-    paths-ignore:
-      - 'docs/**'
-      - 'proposals/**'
-      - '**.adoc'
-      - '**.md'
-      - 'KEYS'
-      - 'LICENSE'
-      - 'NOTICE'
-  push:
-    branches:
-      - main
-      - "release-*"
-    paths-ignore:
-      - 'docs/**'
-      - 'proposals/**'
-      - '**.adoc'
-      - '**.md'
-      - 'KEYS'
-      - 'LICENSE'
-      - 'NOTICE'
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
-  cancel-in-progress: true
-
-jobs:
-  build:
-    name: openshift-build
-    runs-on: ubuntu-20.04
-
-    steps:
-    - name: Checkout code
-      uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
-
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        sudo rm -rf /usr/share/dotnet
-        sudo rm -rf /opt/ghc
-        sudo rm -rf "/usr/local/share/boost"
-        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-        docker rmi $(docker image ls -aq)
-
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
-      with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v1
-      with:
-        go-version: 1.16.x
+name: kamel-config-cluster-ocp3
+description: 'Provides configuration for making available kubernetes cluster on ocp3'
+
+runs:
+  using: "composite"
+  steps:
     - name: Get OpenShift Client (oc)
+      shell: bash
       run: |
         export OPENSHIFT_VERSION=v3.11.0
         export OPENSHIFT_COMMIT=0cbc58b
@@ -108,7 +49,9 @@ jobs:
         sudo mv oc.bin /usr/local/bin/oc
         sudo chmod 755 /usr/local/bin/oc
 
-    - name: Start OpenShift Cluster
+    - id: start-openshift
+      name: Start OpenShift Cluster
+      shell: bash
       run: |
         # Figure out this host's IP address
         IP_ADDR="$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)"
@@ -122,6 +65,9 @@ jobs:
         oc cluster up --public-hostname=$IP_ADDR --enable=persistent-volumes,registry,router
         oc login -u system:admin
 
+        # Export the context used for admin login
+        echo "KUBE_ADMIN_USER_CTX=$(oc config current-context)" >> $GITHUB_ENV
+
         # Wait until we have a ready node in openshift
         TIMEOUT=0
         TIMEOUT_COUNT=60
@@ -141,28 +87,16 @@ jobs:
 
         echo "openshift is deployed and reachable"
 
-    - name: Info
+    - id: info
+      name: Info
+      shell: bash
       run: |
         oc describe nodes
-    - name: Run IT
-      #env:
-      #  TEST_DOCKER_HUB_USERNAME: ${{ secrets.TEST_DOCKER_HUB_USERNAME }}
-      #  TEST_DOCKER_HUB_PASSWORD: ${{ secrets.TEST_DOCKER_HUB_PASSWORD }}
-      #  TEST_GITHUB_PACKAGES_REPO: ${{ secrets.TEST_GITHUB_PACKAGES_REPO }}
-      #  TEST_GITHUB_PACKAGES_USERNAME: ${{ secrets.TEST_GITHUB_PACKAGES_USERNAME }}
-      #  TEST_GITHUB_PACKAGES_PASSWORD: ${{ secrets.TEST_GITHUB_PACKAGES_PASSWORD }}
-      run: |
-        # Compute registry parameters
-        echo "Build project"
-
-        make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images
-
-        # Make the Apache Snapshots or Apache Staging repository enabled by default
-        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
-
-        echo "installing camel k cluster resources"
-        ./kamel install --cluster-setup
 
+    - id: configure-developer-user
+      name: Configure Developer User
+      shell: bash
+      run: |
         # Aggregate pod eviction permission to the default admin role
         cat <<EOF | oc apply -f -
         kind: ClusterRole
@@ -247,6 +181,12 @@ jobs:
         # Login as normal user
         oc login -u developer
 
-        # Then run integration tests
-        make test-integration
-        make test-builder
+        # Export the context used for developer login
+        echo "KUBE_USER_CTX=$(oc config current-context)" >> $GITHUB_ENV
+
+
+    - id: extract-kube-config
+      shell: bash
+      run: |
+        echo "IMAGE_REGISTRY=" >> $GITHUB_ENV
+        echo "IMAGE_REGISTRY_INSECURE=false" >> $GITHUB_ENV
diff --git a/.github/actions/kamel-config-cluster/action.yaml b/.github/actions/kamel-config-cluster/action.yaml
new file mode 100644
index 0000000..2ff0b64
--- /dev/null
+++ b/.github/actions/kamel-config-cluster/action.yaml
@@ -0,0 +1,180 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-config-cluster
+description: 'Delegates to respective cluster action depending on type of requested platform'
+
+inputs:
+  cluster-type:
+    description: 'The type of cluster required: [kind, ocp3, custom]'
+    required: true
+    default: 'kind'
+  kube-config-data:
+    description: 'The kube-config-data - required for custom config only'
+    required: false
+  kube-admin-user-ctx:
+    description: 'The kube-admin-user-ctx - required for custom config only'
+    required: false
+  kube-user-ctx:
+    description: 'The kube-user-ctx - required for custom config only'
+    required: false
+  image-registry:
+    description: 'The image-registry - required for custom config only'
+    required: false
+  image-registry-insecure:
+    description: 'The image-registry-insecure - required for custom config only'
+    required: false
+  opm:
+    description: 'Install opm alongside cluster for bundle-related operations'
+    required: false
+    default: false
+  olm:
+    description: 'Check for & install OLM alongside cluster for bundle-related operations'
+    required: false
+    default: false
+
+runs:
+  using: "composite"
+  steps:
+    #
+    # TODO
+    # Due to lack of if in steps, need to use conditional action which
+    # does not currently include output support so have to put all vars
+    # as environment vars. When either ChristopherHX or github support allow
+    # for alternative then update accordingly.
+    #
+    - id: execute-kind
+      name: Maybe Execute Kind Cluster
+      uses: ./.github/actions/conditional
+      with:
+        if: ${{ inputs.cluster-type == 'kind' }}
+        step: |
+          uses: ./.github/actions/kamel-config-cluster-kind
+
+    - id: execute-ocp3
+      name: Maybe Execute Minishift Cluster
+      uses: ./.github/actions/conditional
+      with:
+        if: ${{ inputs.cluster-type == 'ocp3' }}
+        step: |
+          uses: ./.github/actions/kamel-config-cluster-ocp3
+
+    - id: execute-custom
+      name: Maybe Execute Custom Cluster
+      uses: ./.github/actions/conditional
+      env:
+        KUBE_CONFIG_DATA: ${{ inputs.kube-config-data }}
+        KUBE_ADMIN_USER_CTX: ${{ inputs.kube-admin-user-ctx }}
+        KUBE_USER_CTX: ${{ inputs.kube-user-ctx }}
+        IMAGE_REGISTRY: ${{ inputs.image-registry }}
+        IMAGE_REGISTRY_INSECURE: ${{ inputs.image-registry-insecure }}
+      with:
+        if: ${{ inputs.cluster-type == 'custom' }}
+        step: |
+          uses: ./.github/actions/kamel-config-cluster-custom
+
+    - id: execute-invalid
+      name: Execute Invalid Cluster
+      uses: ./.github/actions/conditional
+      with:
+        if: ${{ inputs.cluster-type != 'kind' &&  inputs.cluster-type != 'ocp3' &&  inputs.cluster-type != 'custom' }}
+        step: |
+          shell: bash
+          run: |
+            echo "Error: Unrecognised platform request for type of cluster. Should be kind, ocp3 or custom."
+            exit 1
+
+    - id: platform-info
+      shell: bash
+      run: |
+        echo "::set-output name=registry::$(echo ${{ env.IMAGE_REGISTRY }})"
+        echo "::set-output name=registry-insecure::$(echo ${{ env.IMAGE_REGISTRY_INSECURE }})"
+        echo "::set-output name=kube-admin-user-ctx::$(echo ${{ env.KUBE_ADMIN_USER_CTX }})"
+        echo "::set-output name=kube-user-ctx::$(echo ${{ env.KUBE_USER_CTX }})"
+
+      #
+      # Install opm if required
+      #
+    - id: install-opm
+      name: Install opm if required
+      shell: bash
+      run: |
+        if [ "${{ inputs.opm }}" == "true" ]; then
+          curl -L https://github.com/operator-framework/operator-registry/releases/download/v1.19.5/linux-amd64-opm -o opm
+          chmod +x opm
+          sudo mv opm /usr/local/bin/
+        fi
+
+      #
+      # Install OLM if required
+      #
+    - id: install-olm
+      name: Install OLM
+      shell: bash
+      run: |
+        if [ "${{ inputs.olm }}" != "true" ]; then
+          # OLM not required
+          echo "OLM not required"
+          exit 0
+        fi
+
+        #
+        # Get current context
+        #
+        echo "Cache current kube context"
+        ctx=$(kubectl config current-context)
+
+        #
+        # Need to be admin so switch to the admin context
+        #
+        echo "Change to kube admin context"
+        kubectl config use-context "${{ steps.platform-info.outputs.kube-admin-user-ctx }}"
+
+        set +e
+        echo "Check if OLM is already installed"
+        kubectl get deployments --all-namespaces | grep olm-operator
+        if [ $? != 0 ]; then
+          set -e
+          echo "OLM not detected on cluster so downloading and installing"
+          kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/crds.yaml
+          # wait for a while to be sure CRDs are installed
+          sleep 1
+          kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/olm.yaml
+        fi
+        set -e
+
+        #
+        # Change back to original context
+        #
+        echo "Return to original kube context"
+        kubectl config use-context "${ctx}"
+
+        echo "Complete"
+
+outputs:
+  image-registry:
+    description: "Registry for storing images"
+    value: ${{ steps.platform-info.outputs.registry }}
+  image-registry-insecure:
+    description: "Whether the image registry require secure/authenticated access"
+    value: ${{ steps.platform-info.outputs.registry-insecure }}
+  kube-admin-user-ctx:
+    description: "The admin user context of the cluster"
+    value: ${{ steps.platform-info.outputs.kube-admin-user-ctx }}
+  kube-user-ctx:
+    description: "The user context of the cluster"
+    value: ${{ steps.platform-info.outputs.kube-user-ctx }}
diff --git a/.github/actions/kamel-install-cluster-setup/action.yml b/.github/actions/kamel-install-cluster-setup/action.yml
new file mode 100644
index 0000000..e1ac5bb
--- /dev/null
+++ b/.github/actions/kamel-install-cluster-setup/action.yml
@@ -0,0 +1,54 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-install-cluster-setup
+description: 'Execute kamel to install the cluster-level artifacts'
+
+inputs:
+  kube-admin-user-ctx:
+    description: "The administration user context of the cluster"
+    required: true
+
+runs:
+  using: "composite"
+  steps:
+    - id: execute-kamel
+      name: Install Camel-K Cluster Resources
+      shell: bash
+      run: |
+        #
+        # Get current context
+        #
+        ctx=$(kubectl config current-context)
+
+        #
+        # Need to be admin so switch to the admin context
+        #
+        kubectl config use-context "${{ inputs.kube-admin-user-ctx }}"
+
+        kamel install --cluster-setup
+
+        #
+        # Change back to original context
+        #
+        kubectl config use-context "${ctx}"
+
+    - id: post-execution
+      shell: bash
+      run: |
+        rm -f /tmp/config
+        export -n KUBECONFIG
diff --git a/.github/actions/kamel-install-knative/action.yml b/.github/actions/kamel-install-knative/action.yml
new file mode 100644
index 0000000..4b33123
--- /dev/null
+++ b/.github/actions/kamel-install-knative/action.yml
@@ -0,0 +1,63 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-install-knative
+description: 'Install Knative artifacts'
+runs:
+  using: "composite"
+  steps:
+    - name: Install Knative
+      shell: bash
+      run: |
+        # Prerequisites
+        sudo wget https://github.com/mikefarah/yq/releases/download/v4.9.6/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq
+
+        export SERVING_VERSION=knative-v1.1.0
+        export EVENTING_VERSION=knative-v1.1.0
+        export KOURIER_VERSION=knative-v1.1.0
+
+        # Serving
+        kubectl apply --filename https://github.com/knative/serving/releases/download/$SERVING_VERSION/serving-crds.yaml
+        curl -L -s https://github.com/knative/serving/releases/download/$SERVING_VERSION/serving-core.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+
+        # Kourier
+        kubectl apply --filename https://github.com/knative-sandbox/net-kourier/releases/download/$KOURIER_VERSION/kourier.yaml
+        kubectl patch configmap/config-network \
+          --namespace knative-serving \
+          --type merge \
+          --patch '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'
+
+        # Eventing
+        kubectl apply --filename https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-crds.yaml
+        curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-core.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+
+        # Eventing channels
+        curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/in-memory-channel.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+
+        # Eventing broker
+        curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/mt-channel-broker.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+
+        # Eventing sugar controller for injection
+        kubectl apply -f https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-sugar-controller.yaml
+
+        # Wait for installation completed
+        echo "Waiting for all pods to be ready in kourier-system"
+        kubectl wait --for=condition=Ready pod --all -n kourier-system --timeout=60s
+        echo "Waiting for all pods to be ready in knative-serving"
+        kubectl wait --for=condition=Ready pod --all -n knative-serving --timeout=60s
+        echo "Waiting for all pods to be ready in knative-eventing"
+        kubectl wait --for=condition=Ready pod --all -n knative-eventing --timeout=60s
diff --git a/.github/actions/kamel-prepare-env/action.yml b/.github/actions/kamel-prepare-env/action.yml
new file mode 100644
index 0000000..f1b5acd
--- /dev/null
+++ b/.github/actions/kamel-prepare-env/action.yml
@@ -0,0 +1,105 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: kamel-prepare-env
+description: 'Initialise the test environment with tools'
+
+runs:
+  using: "composite"
+  steps:
+    #
+    # This is a docker action so its pre-builds the image prior to
+    # running it. The building occurs prior to all steps regardless
+    # of where its located to run. Therefore, it must be run prior to
+    # clean-up since that step removes all docker image in order to
+    # claim back as much space as possible.
+    #
+    - id: read-env-file
+      uses: ./.github/actions/action-dotenv-to-setenv
+      with:
+        env-file: .github/.env
+
+    - name: Cleanup
+      shell: bash
+      run: |
+        ls -lart
+        echo "Initial status:"
+        df -h
+
+        if [ "$RUNNER_OS" == "Linux" ]; then
+          echo "Cleaning up resources:"
+          sudo swapoff -a
+          sudo rm -f /swapfile
+          sudo apt clean
+          sudo rm -rf /usr/share/dotnet
+          sudo rm -rf /opt/ghc
+          sudo rm -rf "/usr/local/share/boost"
+          sudo rm -rf "$AGENT_TOOLSDIRECTORY"
+          df -kh
+          docker rmi $(docker image ls -aq) || true # Don't fail if image is not present
+          df -kh
+        else
+          echo "OS $RUNNER_OS is not yet supported"
+          exit 1
+        fi
+
+        echo "Final status:"
+        df -h
+
+    - name: Set up JDK 11
+      uses: AdoptOpenJDK/install-jdk@v1
+      with:
+        version: "11"
+
+    - name: Set Go
+      uses: actions/setup-go@v2 # Version 2 adds GOBIN to PATH
+      with:
+        go-version: 1.16.x
+
+    - name: (Re-)install kustomize
+      shell: bash
+      run: |
+        # reinstall kustomize to be always on the same version
+        sudo rm $(which kustomize)
+        make kustomize
+
+        # Add kustomize to PATH
+        echo "${{ env.GOPATH }}/bin" >> $GITHUB_PATH
+        which kustomize || { echo 'kustomize not found' ; exit 1; }
+
+    #
+    # Install a version of kubectl for generic access to cluster
+    #
+    - id: install-kubectl
+      uses: azure/setup-kubectl@v1
+      with:
+        version: 'latest'
+
+    - id: report-platform
+      name: Report Platform
+      shell: bash
+      run : |
+        if [ -n "${{ env.TEST_PLATFORM_CLUSTER }}" ]; then
+          echo "::set-output name=platform::$(echo ${{ env.TEST_PLATFORM_CLUSTER }})"
+        else
+          echo "::set-output name=platform::$(echo kind)"
+        fi
+
+outputs:
+  cluster-platform:
+    description: "Preferred environment set by .env file (default 'kind')"
+    value: ${{ steps.report-platform.outputs.platform }}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7831f9e..c8ceb9f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -54,18 +54,19 @@ jobs:
         # TODO: test an all the supported OS
         # [ubuntu-20.04, macos-latest, windows-latest]
         os: [ubuntu-20.04]
+
     runs-on: ${{ matrix.os }}
     steps:
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
-      with:
-        version: "11"
-    - name: Install Go
-      uses: actions/setup-go@v1
-      with:
-        go-version: 1.16.x
     - name: Checkout code
       uses: actions/checkout@v2
+      with:
+        persist-credentials: false
+        submodules: recursive
+
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
+
     - name: Cache modules
       uses: actions/cache@v1
       with:
@@ -73,5 +74,6 @@ jobs:
         key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
         restore-keys: |
           ${{ runner.os }}-go-
+
     - name: Test
       run: make
diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml
index b520ff8..f78cc67 100644
--- a/.github/workflows/builder.yml
+++ b/.github/workflows/builder.yml
@@ -58,72 +58,53 @@ jobs:
     steps:
     - name: Checkout code
       uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
+      with:
+        persist-credentials: false
+        submodules: recursive
 
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        docker rmi $(docker image ls -aq)
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
 
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
+    - id: configure-platform
+      name: Configure Platform
+      uses: ./.github/actions/kamel-config-cluster
       with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v1
+        cluster-type: ${{ steps.prepare-env.outputs.cluster-platform }}
+        kube-config-data: ${{ secrets.KUBE_CONFIG_DATA }}
+        kube-admin-user-ctx: ${{ secrets.KUBE_ADMIN_USER_CTX }}
+        kube-user-ctx: ${{ secrets.KUBE_USER_CTX }}
+        image-registry: ${{ secrets.IMAGE_REGISTRY }}
+        image-registry-insecure: ${{ secrets.IMAGE_REGISTRY_INSECURE }}
+
+
+    - id: build-kamel-binary
+      name: Build Kamel Binary
+      uses: ./.github/actions/kamel-build
       with:
-        go-version: 1.16.x
-    - name: Kubernetes KinD Cluster
-      uses: container-tools/kind-action@v1
+        image-registry: ${{ steps.configure-platform.outputs.image-registry }}
+
+    - name: Install Kamel Cluster Setup
+      uses: ./.github/actions/kamel-install-cluster-setup
       with:
-        version: v0.11.0
-        node_image: kindest/node:v1.21.1@sha256:fae9a58f17f18f06aeac9772ca8b5ac680ebbed985e266f711d936e91d113bad
-    - name: Info
-      run: |
-        kubectl cluster-info
-        kubectl describe nodes
-    - name: Build Operator
-      run: |
-        echo "Build project"
-        export CUSTOM_IMAGE=${KIND_REGISTRY}/apache/camel-k
-        echo "LOCAL_IMAGE_NAME=${CUSTOM_IMAGE}" >> $GITHUB_ENV
-        echo "LOCAL_IMAGE_VERSION=$(make get-version)" >> $GITHUB_ENV
-        make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images images-push
+        kube-admin-user-ctx: ${{ steps.configure-platform.outputs.kube-admin-user-ctx }}
 
-        sudo mv ./kamel /usr/local/bin
     - name: Run IT
-      # Disable registry tests as not compatible with KinD
-      #env:
-      #  TEST_DOCKER_HUB_USERNAME: ${{ secrets.TEST_DOCKER_HUB_USERNAME }}
-      #  TEST_DOCKER_HUB_PASSWORD: ${{ secrets.TEST_DOCKER_HUB_PASSWORD }}
-      #  TEST_GITHUB_PACKAGES_REPO: ${{ secrets.TEST_GITHUB_PACKAGES_REPO }}
-      #  TEST_GITHUB_PACKAGES_USERNAME: ${{ secrets.TEST_GITHUB_PACKAGES_USERNAME }}
-      #  TEST_GITHUB_PACKAGES_PASSWORD: ${{ secrets.TEST_GITHUB_PACKAGES_PASSWORD }}
       env:
         KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY: ${{ matrix.publisher }}
       run: |
-        echo "Installing camel k cluster resources"
-        kamel install --cluster-setup
-
-        # Configure install options
-        export CUSTOM_IMAGE=${{ env.LOCAL_IMAGE_NAME }}
-        export CUSTOM_VERSION=${{ env.LOCAL_IMAGE_VERSION }}
-        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
-        export KAMEL_INSTALL_REGISTRY=$KIND_REGISTRY
-        export KAMEL_INSTALL_REGISTRY_INSECURE=true
+        # Cluster environment
+        export KAMEL_INSTALL_REGISTRY=${{ steps.configure-platform.outputs.image-registry }}
+        export KAMEL_INSTALL_REGISTRY_INSECURE=${{ steps.configure-platform.outputs.image-registry-insecure }}
+        export CUSTOM_IMAGE=${{ steps.build-kamel-binary.outputs.local-image-name }}
+        export CUSTOM_VERSION=${{ steps.build-kamel-binary.outputs.local-image-version }}
         export KAMEL_INSTALL_OPERATOR_IMAGE=${CUSTOM_IMAGE}:${CUSTOM_VERSION}
-        export KAMEL_INSTALL_OPERATOR_ENV_VARS=KAMEL_INSTALL_DEFAULT_KAMELETS=false
-
-        # Configure test options
         export CAMEL_K_TEST_IMAGE_NAME=${CUSTOM_IMAGE}
         export CAMEL_K_TEST_IMAGE_VERSION=${CUSTOM_VERSION}
 
+        # Test options
+        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
+        export KAMEL_INSTALL_OPERATOR_ENV_VARS=KAMEL_INSTALL_DEFAULT_KAMELETS=false
+
         # Then run integration tests
         make test-builder
diff --git a/.github/workflows/knative.yml b/.github/workflows/knative.yml
index e333dbc..950b127 100644
--- a/.github/workflows/knative.yml
+++ b/.github/workflows/knative.yml
@@ -51,112 +51,53 @@ jobs:
   test:
     runs-on: ubuntu-20.04
     steps:
+
     - name: Checkout code
       uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
-
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        sudo rm -rf /usr/share/dotnet
-        sudo rm -rf /opt/ghc
-        sudo rm -rf "/usr/local/share/boost"
-        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-        docker rmi $(docker image ls -aq)
-
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
       with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v1
-      with:
-        go-version: 1.16.x
-    - name: Kubernetes KinD Cluster
-      uses: container-tools/kind-action@v1
-      with:
-        version: v0.11.0
-        node_image: kindest/node:v1.21.1@sha256:fae9a58f17f18f06aeac9772ca8b5ac680ebbed985e266f711d936e91d113bad
-    - name: Info
-      run: |
-        kubectl version
-        kubectl cluster-info
-        kubectl describe nodes
-    - name: Install Knative
-      run: |
-        # Prerequisites
-        sudo wget https://github.com/mikefarah/yq/releases/download/v4.9.6/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq
-
-        export SERVING_VERSION=knative-v1.1.0
-        export EVENTING_VERSION=knative-v1.1.0
-        export KOURIER_VERSION=knative-v1.1.0
-
-        # Serving
-        kubectl apply --filename https://github.com/knative/serving/releases/download/$SERVING_VERSION/serving-crds.yaml
-        curl -L -s https://github.com/knative/serving/releases/download/$SERVING_VERSION/serving-core.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
-
-        # Kourier
-        kubectl apply --filename https://github.com/knative-sandbox/net-kourier/releases/download/$KOURIER_VERSION/kourier.yaml
-        kubectl patch configmap/config-network \
-        --namespace knative-serving \
-        --type merge \
-        --patch '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'
-
-        # Eventing
-        kubectl apply --filename https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-crds.yaml
-        curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-core.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+        persist-credentials: false
+        submodules: recursive
 
-        # Eventing channels
-        curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/in-memory-channel.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
 
-        # Eventing broker
-        curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/mt-channel-broker.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
+    - id: configure-platform
+      name: Configure Platform
+      uses: ./.github/actions/kamel-config-cluster
+      with:
+        cluster-type: ${{ steps.prepare-env.outputs.cluster-platform }}
 
-        # Eventing sugar controller for injection
-        kubectl apply -f https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-sugar-controller.yaml
+    - name: Install Knative
+      uses: ./.github/actions/kamel-install-knative
 
-        # Wait for installation completed
-        echo "Waiting for all pods to be ready in kourier-system"
-        kubectl wait --for=condition=Ready pod --all -n kourier-system --timeout=60s
-        echo "Waiting for all pods to be ready in knative-serving"
-        kubectl wait --for=condition=Ready pod --all -n knative-serving --timeout=60s
-        echo "Waiting for all pods to be ready in knative-eventing"
-        kubectl wait --for=condition=Ready pod --all -n knative-eventing --timeout=60s
+    - id: build-kamel-binary
+      name: Build Kamel Binary
+      uses: ./.github/actions/kamel-build
+      with:
+        image-registry: ${{ steps.configure-platform.outputs.image-registry }}
 
-    - name: Build Operator
-      run: |
-        echo "Build project"
-        export CUSTOM_IMAGE=${KIND_REGISTRY}/apache/camel-k
-        echo "LOCAL_IMAGE_NAME=${CUSTOM_IMAGE}" >> $GITHUB_ENV
-        echo "LOCAL_IMAGE_VERSION=$(make get-version)" >> $GITHUB_ENV
-        make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images images-push
+    - name: Install Kamel Cluster Setup
+      uses: ./.github/actions/kamel-install-cluster-setup
+      with:
+        kube-admin-user-ctx: ${{ steps.configure-platform.outputs.kube-admin-user-ctx }}
 
-        sudo mv ./kamel /usr/local/bin
     - name: Run IT
       run: |
-        echo "Installing camel k cluster resources"
-        kamel install --cluster-setup
-
-        # Configure install options
-        export CUSTOM_IMAGE=${{ env.LOCAL_IMAGE_NAME }}
-        export CUSTOM_VERSION=${{ env.LOCAL_IMAGE_VERSION }}
-        export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
-        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
-        export KAMEL_INSTALL_REGISTRY=$KIND_REGISTRY
-        export KAMEL_INSTALL_REGISTRY_INSECURE=true
+        # Cluster environment
+        export KAMEL_INSTALL_REGISTRY=${{ steps.configure-platform.outputs.image-registry }}
+        export KAMEL_INSTALL_REGISTRY_INSECURE=${{ steps.configure-platform.outputs.image-registry-insecure }}
+        export CUSTOM_IMAGE=${{ steps.build-kamel-binary.outputs.local-image-name }}
+        export CUSTOM_VERSION=${{ steps.build-kamel-binary.outputs.local-image-version }}
         export KAMEL_INSTALL_OPERATOR_IMAGE=${CUSTOM_IMAGE}:${CUSTOM_VERSION}
-
-        # Configure test options
         export CAMEL_K_TEST_IMAGE_NAME=${CUSTOM_IMAGE}
         export CAMEL_K_TEST_IMAGE_VERSION=${CUSTOM_VERSION}
 
+        # Test options
+        export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
+        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
+        export KAMEL_INSTALL_OPERATOR_ENV_VARS=KAMEL_INSTALL_DEFAULT_KAMELETS=false
+
         # Then run integration tests
         make test-knative
 
@@ -165,119 +106,61 @@ jobs:
     steps:
       - name: Checkout code
         uses: actions/checkout@v2
-      - name: Cleanup
-        run: |
-          ls -lart
-          echo "Initial status:"
-          df -h
+        with:
+          persist-credentials: false
+          submodules: recursive
 
-          echo "Cleaning up resources:"
-          sudo swapoff -a
-          sudo rm -f /swapfile
-          sudo apt clean
-          sudo rm -rf /usr/share/dotnet
-          sudo rm -rf /opt/ghc
-          sudo rm -rf "/usr/local/share/boost"
-          sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-          docker rmi $(docker image ls -aq)
+      - id: prepare-env
+        name: Prepare Test Environment
+        uses: ./.github/actions/kamel-prepare-env
 
-          echo "Final status:"
-          df -h
-      - name: Set up JDK 11
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: "11"
-      - name: Set Go
-        uses: actions/setup-go@v1
-        with:
-          go-version: 1.16.x
       - name: Get YAKS
         run: |
           export YAKS_VERSION=0.4.0
           curl --fail -L https://github.com/citrusframework/yaks/releases/download/v${YAKS_VERSION}/yaks-${YAKS_VERSION}-linux-64bit.tar.gz -o yaks.tar.gz
           tar -zxf yaks.tar.gz
           sudo mv yaks /usr/local/bin/
-      - name: Kubernetes KinD Cluster
-        uses: container-tools/kind-action@v1
+
+      - id: configure-platform
+        name: Configure Platform
+        uses: ./.github/actions/kamel-config-cluster
         with:
-          version: v0.11.0
-          node_image: kindest/node:v1.21.1@sha256:fae9a58f17f18f06aeac9772ca8b5ac680ebbed985e266f711d936e91d113bad
-      - name: Info
-        run: |
-          kubectl version
-          kubectl cluster-info
-          kubectl describe nodes
+          cluster-type: ${{ steps.prepare-env.outputs.cluster-platform }}
+
       - name: Install YAKS
         run: |
           yaks install --cluster-setup
-      - name: Install Knative
-        run: |
-          # Prerequisites
-          sudo wget https://github.com/mikefarah/yq/releases/download/v4.9.6/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq
-
-          export SERVING_VERSION=knative-v1.1.0
-          export EVENTING_VERSION=knative-v1.1.0
-          export KOURIER_VERSION=knative-v1.1.0
-
-          # Serving
-          kubectl apply --filename https://github.com/knative/serving/releases/download/$SERVING_VERSION/serving-crds.yaml
-          curl -L -s https://github.com/knative/serving/releases/download/$SERVING_VERSION/serving-core.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
-
-          # Kourier
-          kubectl apply --filename https://github.com/knative-sandbox/net-kourier/releases/download/$KOURIER_VERSION/kourier.yaml
-          kubectl patch configmap/config-network \
-          --namespace knative-serving \
-          --type merge \
-          --patch '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'
-
-          # Eventing
-          kubectl apply --filename https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-crds.yaml
-          curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-core.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
-
-          # Eventing channels
-          curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/in-memory-channel.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
 
-          # Eventing broker
-          curl -L -s https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/mt-channel-broker.yaml | head -n -1 | yq e 'del(.spec.template.spec.containers[].resources)' - | kubectl apply -f -
-
-          # Eventing sugar controller for injection
-          kubectl apply -f https://github.com/knative/eventing/releases/download/$EVENTING_VERSION/eventing-sugar-controller.yaml
+      - name: Install Knative
+        uses: ./.github/actions/kamel-install-knative
 
-          # Wait for installation completed
-          echo "Waiting for all pods to be ready in kourier-system"
-          kubectl wait --for=condition=Ready pod --all -n kourier-system --timeout=60s
-          echo "Waiting for all pods to be ready in knative-serving"
-          kubectl wait --for=condition=Ready pod --all -n knative-serving --timeout=60s
-          echo "Waiting for all pods to be ready in knative-eventing"
-          kubectl wait --for=condition=Ready pod --all -n knative-eventing --timeout=60s
+      - id: build-kamel-binary
+        name: Build Kamel Binary
+        uses: ./.github/actions/kamel-build
+        with:
+          image-registry: ${{ steps.configure-platform.outputs.image-registry }}
 
-      - name: Build Operator
-        run: |
-          echo "Build project"
-          export CUSTOM_IMAGE=${KIND_REGISTRY}/apache/camel-k
-          echo "LOCAL_IMAGE_NAME=${CUSTOM_IMAGE}" >> $GITHUB_ENV
-          echo "LOCAL_IMAGE_VERSION=$(make get-version)" >> $GITHUB_ENV
-          make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images images-push
+      - name: Install Kamel Cluster Setup
+        uses: ./.github/actions/kamel-install-cluster-setup
+        with:
+          kube-admin-user-ctx: ${{ steps.configure-platform.outputs.kube-admin-user-ctx }}
 
-          sudo mv ./kamel /usr/local/bin
       - name: Run IT
         run: |
-          echo "Installing camel k cluster resources"
-          kamel install --cluster-setup
-
-          # Configure install options
-          export CUSTOM_IMAGE=${{ env.LOCAL_IMAGE_NAME }}
-          export CUSTOM_VERSION=${{ env.LOCAL_IMAGE_VERSION }}
-          export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
-          export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
-          export KAMEL_INSTALL_REGISTRY=$KIND_REGISTRY
-          export KAMEL_INSTALL_REGISTRY_INSECURE=true
+          # Cluster environment
+          export KAMEL_INSTALL_REGISTRY=${{ steps.configure-platform.outputs.image-registry }}
+          export KAMEL_INSTALL_REGISTRY_INSECURE=${{ steps.configure-platform.outputs.image-registry-insecure }}
+          export CUSTOM_IMAGE=${{ steps.build-kamel-binary.outputs.local-image-name }}
+          export CUSTOM_VERSION=${{ steps.build-kamel-binary.outputs.local-image-version }}
           export KAMEL_INSTALL_OPERATOR_IMAGE=${CUSTOM_IMAGE}:${CUSTOM_VERSION}
-
-          # Configure test options
-          export CAMEL_K_TEST_IMAGE_NAME=$KIND_REGISTRY/apache/camel-k
+          export CAMEL_K_TEST_IMAGE_NAME=${CUSTOM_IMAGE}
           export CAMEL_K_TEST_IMAGE_VERSION=${CUSTOM_VERSION}
 
+          # Test options
+          export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
+          export KAMEL_INSTALL_OPERATOR_ENV_VARS=KAMEL_INSTALL_DEFAULT_KAMELETS=false
+          export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
+
           # Install Yaks globally
           yaks install
 
diff --git a/.github/workflows/kubernetes.yml b/.github/workflows/kubernetes.yml
index 654d70a..ca23a01 100644
--- a/.github/workflows/kubernetes.yml
+++ b/.github/workflows/kubernetes.yml
@@ -55,75 +55,46 @@ jobs:
     steps:
     - name: Checkout code
       uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
+      with:
+        persist-credentials: false
+        submodules: recursive
 
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        sudo rm -rf /usr/share/dotnet
-        sudo rm -rf /opt/ghc
-        sudo rm -rf "/usr/local/share/boost"
-        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-        docker rmi $(docker image ls -aq)
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
 
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
+    - id: configure-platform
+      name: Configure Platform
+      uses: ./.github/actions/kamel-config-cluster
       with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v1
+        cluster-type: ${{ steps.prepare-env.outputs.cluster-platform }}
+
+    - id: build-kamel-binary
+      name: Build Kamel Binary
+      uses: ./.github/actions/kamel-build
       with:
-        go-version: 1.16.x
-    - name: Kubernetes KinD Cluster
-      uses: container-tools/kind-action@v1
+        image-registry: ${{ steps.configure-platform.outputs.image-registry }}
+
+    - name: Install Kamel Cluster Setup
+      uses: ./.github/actions/kamel-install-cluster-setup
       with:
-        version: v0.11.0
-        node_image: kindest/node:v1.21.1@sha256:fae9a58f17f18f06aeac9772ca8b5ac680ebbed985e266f711d936e91d113bad
-    - name: Info
-      run: |
-        kubectl cluster-info
-        kubectl describe nodes
-    - name: Build Operator
-      run: |
-        echo "Build project"
-        export CUSTOM_IMAGE=${KIND_REGISTRY}/apache/camel-k
-        echo "LOCAL_IMAGE_NAME=${CUSTOM_IMAGE}" >> $GITHUB_ENV
-        echo "LOCAL_IMAGE_VERSION=$(make get-version)" >> $GITHUB_ENV
-        make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images images-push
+        kube-admin-user-ctx: ${{ steps.configure-platform.outputs.kube-admin-user-ctx }}
 
-        sudo mv ./kamel /usr/local/bin
     - name: Run IT
-      # Disable registry tests as not compatible with KinD
-      #env:
-      #  TEST_DOCKER_HUB_USERNAME: ${{ secrets.TEST_DOCKER_HUB_USERNAME }}
-      #  TEST_DOCKER_HUB_PASSWORD: ${{ secrets.TEST_DOCKER_HUB_PASSWORD }}
-      #  TEST_GITHUB_PACKAGES_REPO: ${{ secrets.TEST_GITHUB_PACKAGES_REPO }}
-      #  TEST_GITHUB_PACKAGES_USERNAME: ${{ secrets.TEST_GITHUB_PACKAGES_USERNAME }}
-      #  TEST_GITHUB_PACKAGES_PASSWORD: ${{ secrets.TEST_GITHUB_PACKAGES_PASSWORD }}
       run: |
-        echo "Installing camel k cluster resources"
-        kamel install --cluster-setup
-
-        # Configure install options
-        export CUSTOM_IMAGE=${{ env.LOCAL_IMAGE_NAME }}
-        export CUSTOM_VERSION=${{ env.LOCAL_IMAGE_VERSION }}
-        export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
-        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
-        export KAMEL_INSTALL_REGISTRY=$KIND_REGISTRY
-        export KAMEL_INSTALL_REGISTRY_INSECURE=true
+        # Cluster environment
+        export KAMEL_INSTALL_REGISTRY=${{ steps.configure-platform.outputs.image-registry }}
+        export KAMEL_INSTALL_REGISTRY_INSECURE=${{ steps.configure-platform.outputs.image-registry-insecure }}
+        export CUSTOM_IMAGE=${{ steps.build-kamel-binary.outputs.local-image-name }}
+        export CUSTOM_VERSION=${{ steps.build-kamel-binary.outputs.local-image-version }}
         export KAMEL_INSTALL_OPERATOR_IMAGE=${CUSTOM_IMAGE}:${CUSTOM_VERSION}
-
-        # Configure test options
         export CAMEL_K_TEST_IMAGE_NAME=${CUSTOM_IMAGE}
         export CAMEL_K_TEST_IMAGE_VERSION=${CUSTOM_VERSION}
 
+        # Test options
+        export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
+        export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
+
         # Then run integration tests
         make test-integration
         make test-service-binding
diff --git a/.github/workflows/local.yml b/.github/workflows/local.yml
index a1a0856..16d8eb6 100644
--- a/.github/workflows/local.yml
+++ b/.github/workflows/local.yml
@@ -55,33 +55,20 @@ jobs:
     steps:
     - name: Checkout code
       uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
+      with:
+        persist-credentials: false
+        submodules: recursive
 
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        docker rmi $(docker image ls -aq)
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
 
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
-      with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v1
+    - id: build-kamel-binary
+      name: Build Kamel Binary
+      uses: ./.github/actions/kamel-build
       with:
-        go-version: 1.16.x
-    - name: Build Kamel
-      run: |
-        echo "Build project"
-        make build-kamel
-        sudo mv ./kamel /usr/local/bin
+        make-rules: 'build-kamel'
+
     - name: Run IT
       run: |
         # Configure staging repos
diff --git a/.github/workflows/openshift.yml b/.github/workflows/openshift.yml
index c7cd72d..64d28b6 100644
--- a/.github/workflows/openshift.yml
+++ b/.github/workflows/openshift.yml
@@ -55,198 +55,34 @@ jobs:
     steps:
     - name: Checkout code
       uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
-
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        sudo rm -rf /usr/share/dotnet
-        sudo rm -rf /opt/ghc
-        sudo rm -rf "/usr/local/share/boost"
-        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-        docker rmi $(docker image ls -aq)
-
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
       with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v1
-      with:
-        go-version: 1.16.x
-    - name: Get OpenShift Client (oc)
-      run: |
-        export OPENSHIFT_VERSION=v3.11.0
-        export OPENSHIFT_COMMIT=0cbc58b
-        export MAVEN_OPTS=-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
-
-        sudo rm -f /etc/resolv.conf
-        sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
-        sudo sh -c 'echo "DNS=8.8.8.8 4.4.4.4" >> /etc/systemd/resolved.conf'
-        sudo service systemd-resolved restart
-
-        # set docker0 to promiscuous mode
-        sudo ip link set docker0 promisc on
-
-        # Download and install the oc binary
-        sudo mount --make-shared /
-
-        sudo service docker stop
-        sudo echo '{"insecure-registries": ["172.30.0.0/16"]}' | sudo tee /etc/docker/daemon.json > /dev/null
-        sudo service docker start
-
-        DOWNLOAD_URL=https://github.com/openshift/origin/releases/download/$OPENSHIFT_VERSION/openshift-origin-client-tools-$OPENSHIFT_VERSION-$OPENSHIFT_COMMIT-linux-64bit.tar.gz
-        wget -O client.tar.gz ${DOWNLOAD_URL}
-        tar xvzOf client.tar.gz > oc.bin
-        sudo mv oc.bin /usr/local/bin/oc
-        sudo chmod 755 /usr/local/bin/oc
-
-    - name: Start OpenShift Cluster
-      run: |
-        # Figure out this host's IP address
-        IP_ADDR="$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)"
+        persist-credentials: false
+        submodules: recursive
 
-        # Setup cluster dir
-        sudo mkdir -p /home/runner/lib/oc
-        sudo chmod 777 /home/runner/lib/oc
-        cd /home/runner/lib/oc
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
 
-        # Start OpenShift
-        oc cluster up --public-hostname=$IP_ADDR --enable=persistent-volumes,registry,router
-        oc login -u system:admin
-
-        # Wait until we have a ready node in openshift
-        TIMEOUT=0
-        TIMEOUT_COUNT=60
-        until [ $TIMEOUT -eq $TIMEOUT_COUNT ]; do
-          if [ -n "$(oc get nodes | grep Ready)" ]; then
-            break
-          fi
-          echo "openshift is not up yet"
-          TIMEOUT=$((TIMEOUT+1))
-          sleep 5
-        done
+    - id: configure-platform
+      name: Configure Platform
+      uses: ./.github/actions/kamel-config-cluster
+      with:
+        cluster-type: 'ocp3'
 
-        if [ $TIMEOUT -eq $TIMEOUT_COUNT ]; then
-          echo "Failed to start openshift"
-          exit 1
-        fi
+    - id: build-kamel-binary
+      name: Build Kamel Binary
+      uses: ./.github/actions/kamel-build
 
-        echo "openshift is deployed and reachable"
+    - name: Install Kamel Cluster Setup
+      uses: ./.github/actions/kamel-install-cluster-setup
+      with:
+        kube-admin-user-ctx: ${{ steps.configure-platform.outputs.kube-admin-user-ctx }}
 
-    - name: Info
-      run: |
-        oc describe nodes
     - name: Run IT
-      #env:
-      #  TEST_DOCKER_HUB_USERNAME: ${{ secrets.TEST_DOCKER_HUB_USERNAME }}
-      #  TEST_DOCKER_HUB_PASSWORD: ${{ secrets.TEST_DOCKER_HUB_PASSWORD }}
-      #  TEST_GITHUB_PACKAGES_REPO: ${{ secrets.TEST_GITHUB_PACKAGES_REPO }}
-      #  TEST_GITHUB_PACKAGES_USERNAME: ${{ secrets.TEST_GITHUB_PACKAGES_USERNAME }}
-      #  TEST_GITHUB_PACKAGES_PASSWORD: ${{ secrets.TEST_GITHUB_PACKAGES_PASSWORD }}
       run: |
-        # Compute registry parameters
-        echo "Build project"
-
-        make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images
-
         # Make the Apache Snapshots or Apache Staging repository enabled by default
         export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
 
-        echo "installing camel k cluster resources"
-        ./kamel install --cluster-setup
-
-        # Aggregate pod eviction permission to the default admin role
-        cat <<EOF | oc apply -f -
-        kind: ClusterRole
-        apiVersion: rbac.authorization.k8s.io/v1
-        metadata:
-          name: camel-k-test:eviction
-          labels:
-            rbac.authorization.k8s.io/aggregate-to-admin: "true"
-        rules:
-        - apiGroups: [""]
-          resources: ["pods/eviction"]
-          verbs: ["create"]
-        EOF
-
-        # Grant nodes permission to the default developer user
-        cat <<EOF | oc apply -f -
-        kind: ClusterRole
-        apiVersion: rbac.authorization.k8s.io/v1
-        metadata:
-          name: camel-k-test:nodes
-        rules:
-        - apiGroups: [""]
-          resources: ["nodes"]
-          verbs: ["get","list"]
-        EOF
-        cat <<EOF | oc apply -f -
-        kind: ClusterRoleBinding
-        apiVersion: rbac.authorization.k8s.io/v1
-        metadata:
-          name: camel-k-test:nodes
-        subjects:
-        - kind: User
-          name: developer
-        roleRef:
-          kind: ClusterRole
-          name: camel-k-test:nodes
-          apiGroup: rbac.authorization.k8s.io
-        EOF
-
-        # Aggregate finalizers permission to the default admin role
-        cat <<EOF | oc apply -f -
-        kind: ClusterRole
-        apiVersion: rbac.authorization.k8s.io/v1
-        metadata:
-          name: camel-k-test:finalizers
-          labels:
-            rbac.authorization.k8s.io/aggregate-to-admin: "true"
-        rules:
-        - apiGroups: ["camel.apache.org"]
-          resources: ["*/finalizers"]
-          verbs: ["update"]
-        EOF
-
-        # Grant read permission on the Kubernetes Service to the default developer user
-        # Required by the HTTP proxy tests
-        cat <<EOF | oc apply -f -
-        kind: ClusterRole
-        apiVersion: rbac.authorization.k8s.io/v1
-        metadata:
-          name: camel-k-test:kubernetes-service
-        rules:
-        - apiGroups: [""]
-          resources: ["services"]
-          verbs: ["get"]
-          resourceNames: ["kubernetes"]
-        EOF
-        cat <<EOF | oc apply -f -
-        kind: RoleBinding
-        apiVersion: rbac.authorization.k8s.io/v1
-        metadata:
-          namespace: default
-          name: camel-k-test:kubernetes-service
-        subjects:
-        - kind: User
-          name: developer
-        roleRef:
-          kind: ClusterRole
-          name: camel-k-test:kubernetes-service
-          apiGroup: rbac.authorization.k8s.io
-        EOF
-
-        # Login as normal user
-        oc login -u developer
-
         # Then run integration tests
         make test-integration
         make test-builder
diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml
index f85cdfb..8b5d1ce 100644
--- a/.github/workflows/upgrade.yml
+++ b/.github/workflows/upgrade.yml
@@ -55,108 +55,65 @@ jobs:
     steps:
     - name: Checkout code
       uses: actions/checkout@v2
-    - name: Cleanup
-      run: |
-        ls -lart
-        echo "Initial status:"
-        df -h
-
-        echo "Cleaning up resources:"
-        sudo swapoff -a
-        sudo rm -f /swapfile
-        sudo apt clean
-        docker rmi $(docker image ls -aq)
-
-        echo "Final status:"
-        df -h
-    - name: Set up JDK 11
-      uses: AdoptOpenJDK/install-jdk@v1
-      with:
-        version: "11"
-    - name: Set Go
-      uses: actions/setup-go@v2
       with:
-        go-version: 1.16.x
-    - name: Set up opm tool
-      run: |
-        curl -L https://github.com/operator-framework/operator-registry/releases/download/v1.19.5/linux-amd64-opm -o opm
-        chmod +x opm
-        sudo mv opm /usr/local/bin/
-    - name: Kubernetes KinD Cluster
-      uses: container-tools/kind-action@v1
+        persist-credentials: false
+        submodules: recursive
+
+    - id: prepare-env
+      name: Prepare Test Environment
+      uses: ./.github/actions/kamel-prepare-env
+
+    - id: configure-platform
+      name: Configure Platform
+      uses: ./.github/actions/kamel-config-cluster
       with:
-        version: v0.11.0
-        node_image: kindest/node:v1.21.1@sha256:fae9a58f17f18f06aeac9772ca8b5ac680ebbed985e266f711d936e91d113bad
-    - name: Info
-      run: |
-        kubectl cluster-info
-        kubectl describe nodes
-    - name: Install OLM
-      run: |
-        kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/crds.yaml
-        # wait for a while to be sure CRDs are installed
-        sleep 1
-        kubectl apply -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.17.0/olm.yaml
-    - name: Get Kamel CLI
+        cluster-type: ${{ steps.prepare-env.outputs.cluster-platform }}
+        opm: true
+        olm: true
+
+    - name: Get Released Kamel CLI
+      shell: bash
       run: |
         export KAMEL_VERSION=$(make get-last-released-version)
         curl -L https://github.com/apache/camel-k/releases/download/v${KAMEL_VERSION}/camel-k-client-${KAMEL_VERSION}-linux-64bit.tar.gz -o kamel.tar.gz
         tar -zxf kamel.tar.gz
         sudo mv kamel /usr/local/bin/
-    - name: Build Operator
-      run: |
-        echo "Build project"
-        export CUSTOM_IMAGE=${KIND_REGISTRY}/apache/camel-k
-        echo "LOCAL_IMAGE_NAME=${CUSTOM_IMAGE}" >> $GITHUB_ENV
-        echo "LOCAL_IMAGE_VERSION=$(make get-version)" >> $GITHUB_ENV
-        make PACKAGE_ARTIFACTS_STRATEGY=download build package-artifacts images images-push
-    - name: Build Operator bundle
-      run: |
-        echo "Build Operator bundle"
-
-        # reinstall kustomize to be always on the same version
-        sudo rm $(which kustomize)
-
-        make kustomize
-
-        # replace image
-        $(cd config/manifests && kustomize edit set image "docker.io/apache/camel-k=${{ env.LOCAL_IMAGE_NAME }}:${{ env.LOCAL_IMAGE_VERSION }}")
-
-        # Patch CSV with the 'replaces' field to define the upgrade graph
-        # Use sed as the manifest/bases file is not included in the kustomize config
-        BASE_VERSION=$(echo ${{ env.LOCAL_IMAGE_VERSION }} | grep -Po "\d.\d.\d")
-        sed -i "/  version: ${BASE_VERSION}/a \ \ replaces: camel-k-operator.v$(make get-last-released-version)" config/manifests/bases/camel-k.clusterserviceversion.yaml
-        export CUSTOM_IMAGE=${{ env.LOCAL_IMAGE_NAME }}
-        export LOCAL_IMAGE_BUNDLE=${KIND_REGISTRY}/apache/camel-k-bundle:${{ env.LOCAL_IMAGE_VERSION }}
-        echo "LOCAL_IMAGE_BUNDLE=${LOCAL_IMAGE_BUNDLE}" >> $GITHUB_ENV
-        export PREV_XY_CHANNEL=stable-$(make get-last-released-version | grep -Po "\d.\d")
-        echo "PREV_XY_CHANNEL=${PREV_XY_CHANNEL}" >> $GITHUB_ENV
-        export NEW_XY_CHANNEL=stable-$(make get-version | grep -Po "\d.\d")
-        echo "NEW_XY_CHANNEL=${NEW_XY_CHANNEL}" >> $GITHUB_ENV
-        make bundle-build BUNDLE_IMAGE_NAME=${LOCAL_IMAGE_BUNDLE} DEFAULT_CHANNEL="${NEW_XY_CHANNEL}" CHANNELS="${NEW_XY_CHANNEL}"
-        docker push ${LOCAL_IMAGE_BUNDLE}
-    - name: Create new index image
-      run: |
-        export LOCAL_IIB=${KIND_REGISTRY}/apache/camel-k-iib:${{ env.LOCAL_IMAGE_VERSION }}
-        echo "LOCAL_IIB=${LOCAL_IIB}" >> $GITHUB_ENV
-        sudo opm index add --bundles ${{ env.LOCAL_IMAGE_BUNDLE }} -c docker --from-index quay.io/operatorhubio/catalog:latest --tag ${LOCAL_IIB} --skip-tls
-        docker push ${LOCAL_IIB}
+        echo "Kamel version installed: $(kamel version)"
+
+    - id: build-kamel-binary
+      name: Build Kamel Binary
+      uses: ./.github/actions/kamel-build
+      with:
+        image-registry: ${{ steps.configure-platform.outputs.image-registry }}
+        # Avoid overwriting last-released version of binary
+        install-kamel-binary: false
+
+    - id: build-kamel-bundle
+      name: Build Kamel Metadata Bundle
+      uses: ./.github/actions/kamel-build-bundle
+      with:
+        image-registry: ${{ steps.configure-platform.outputs.image-registry }}
+        local-image-name: ${{ steps.build-kamel-binary.outputs.local-image-name }}
+        local-image-version: ${{ steps.build-kamel-binary.outputs.local-image-version }}
+
     - name: Run IT
       run: |
         # Use the last released Kamel CLI
         export RELEASED_KAMEL_BIN=/usr/local/bin/kamel
 
+        echo "Kamel version: $(${RELEASED_KAMEL_BIN} version)"
+
         # Configure install options
-        export CUSTOM_IMAGE=${{ env.LOCAL_IMAGE_NAME }}
-        export CUSTOM_VERSION=${{ env.LOCAL_IMAGE_VERSION }}
+        export CUSTOM_IMAGE=${{ steps.build-kamel-binary.outputs.local-image-name }}
+        export CUSTOM_VERSION=${{ steps.build-kamel-binary.outputs.local-image-version }}
         export KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY=Spectrum
         export KAMEL_INSTALL_MAVEN_REPOSITORIES=$(make get-staging-repo)
-        export KAMEL_INSTALL_REGISTRY=${KIND_REGISTRY}
-        export KAMEL_INSTALL_REGISTRY_INSECURE=true
+        export KAMEL_INSTALL_REGISTRY=${{ steps.configure-platform.outputs.image-registry }}
+        export KAMEL_INSTALL_REGISTRY_INSECURE=${{ steps.configure-platform.outputs.image-registry-insecure }}
 
         # Configure test options
         export CAMEL_K_PREV_IIB=quay.io/operatorhubio/catalog:latest
-        export CAMEL_K_NEW_IIB=${{ env.LOCAL_IIB }}
+        export CAMEL_K_NEW_IIB=${{ steps.build-kamel-bundle.outputs.local-image-bundle-index }}
         export KAMEL_K_TEST_RELEASE_VERSION=$(make get-last-released-version)
         export KAMEL_K_TEST_OPERATOR_CURRENT_IMAGE=${CUSTOM_IMAGE}:${CUSTOM_VERSION}
         export CAMEL_K_PREV_UPGRADE_CHANNEL=${{ env.PREV_XY_CHANNEL }}
diff --git a/.gitmodules b/.gitmodules
index 38b2437..aa99c61 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,11 @@
 [submodule ".github/actions/changelog"]
 	path = .github/actions/changelog
 	url = https://github.com/CharMixer/auto-changelog-action
+[submodule ".github/actions/conditional"]
+	path = .github/actions/conditional
+	url = https://github.com/ChristopherHX/conditional.git
+	branch = 3fce4b7a3171a839b482306f9fd3aba0c2112a24
+[submodule ".github/actions/action-dotenv-to-setenv"]
+	path = .github/actions/action-dotenv-to-setenv
+        url = https://github.com/c-py/action-dotenv-to-setenv.git
+	branch = tags/v3
diff --git a/script/Makefile b/script/Makefile
index 038e15b..631e10b 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -319,6 +319,9 @@ images-push-staging:
 	docker tag $(CUSTOM_IMAGE):$(CUSTOM_VERSION) $(STAGING_IMAGE_NAME):$(CUSTOM_VERSION)
 	docker push $(STAGING_IMAGE_NAME):$(CUSTOM_VERSION)
 
+get-image:
+	@echo $(CUSTOM_IMAGE)
+
 get-version:
 	@echo $(CUSTOM_VERSION)