Repository: tektoncd/operator
Pull request #328 (2021-06-11 14:58:33)

Adds params to customize TektonAddon component on OpenShift
- This adds params in TektonConfig which would be copied to Tekton Addon
CR to customize installation of different components of Addons.
- If the params are not passed in TektonConfig CR, controller will add them
with default values.
- User can change values in TektonConfig to change the component installation
of Addon.
- If Addon is created through TektonConfig CR, and if later values are changed in
Addon CR, it will get overwritten by TektonConfig CR values.

Signed-off-by: Shivam Mukhade <smukhade@redhat.com>

**TektonConfig CR**
```
apiVersion: operator.tekton.dev/v1alpha1
kind: TektonConfig
metadata:
  name: config
spec:
  profile: all
  targetNamespace: openshift-pipelines
  addon:
    params:
    - name: clusterTasks
      value: "true"
    - name: pipelineTemplates
      value: "true"

```

<!-- Describe your changes here- ideally you can get that description straight from
your descriptive commit message(s)! -->

# Submitter Checklist

These are the criteria that every PR should meet, please check them off as you
review them:

- [x] Includes [tests](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if functionality changed/added)
- [x] Includes [docs](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if user facing)
- [x] Commit messages follow [commit message best practices](https://github.com/tektoncd/community/blob/master/standards.md#commit-messages)

_See [the contribution guide](https://github.com/tektoncd/operator/blob/master/CONTRIBUTING.md) for more details._

# Release Notes

<!--
Describe any user facing changes here, or delete this block.

Examples of user facing changes:
- API changes
- Bug fixes
- Any changes in behavior
- Changes requiring upgrade notices or deprecation warnings

For pull requests with a release note:

```release-note
Your release note here
```

For pull requests that require additional action from users switching to the new release, include the string "action required" (case insensitive) in the release note:

```release-note
action required: your release note here
```

For pull requests that don't need to be mentioned at release time, use the `/release-note-none` Prow command to add the `release-note-none` label to the PR. You can also write the string "NONE" as a release note in your PR description:

```release-note
NONE
```
-->
```
User can customize installation of TektonAddon Component by passing params in TektonConfig CR if addon is created through it
or directly in TektonAddon.

If params are not passed, controller will add params with default values.

Addons params:

- `clusterTask` (Default: true) Installs ClusterTask
- `pipelinesTemplates` (Default: true) Installs PipelinesTemplates

*This is only for OpenShift Platform
```


sm43: /cc @nikhil-thomas @vdemeester @savitaashture 
Tests are yet to be added. but can be reviewed :D
/hold
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/common/validate.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/328/pull-tekton-operator-go-coverage/1403366179669544963/artifacts/line-cov.html#file5) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/tektonconfig/extension/addon.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/328/pull-tekton-operator-go-coverage/1403366179669544963/artifacts/line-cov.html#file6) | 75.6% | 66.7% | -8.9

nikhil-thomas: /approve
tekton-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/tektoncd/operator/pull/328#issuecomment-860009464" title="Approved">nikhil-thomas</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=tektoncd%2Foperator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/tektoncd/operator/blob/main/OWNERS)~~ [nikhil-thomas]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/common/validate.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/328/pull-tekton-operator-go-coverage/1404285109141508099/artifacts/line-cov.html#file5) | Do not exist | 96.6% | 
[pkg/reconciler/openshift/tektonconfig/extension/addon.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/328/pull-tekton-operator-go-coverage/1404285109141508099/artifacts/line-cov.html#file6) | 75.6% | 66.7% | -8.9

sm43: /hold cancel
savitaashture: @sm43 could you rebase ?

/hold
tekton-robot: New changes are detected. LGTM label has been removed.
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/common/validate.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/328/pull-tekton-operator-go-coverage/1404466681908039680/artifacts/line-cov.html#file5) | Do not exist | 96.6% | 
[pkg/reconciler/openshift/tektonconfig/extension/addon.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/328/pull-tekton-operator-go-coverage/1404466681908039680/artifacts/line-cov.html#file6) | 75.6% | 66.7% | -8.9

nikhil-thomas: /lgtm

Patch:
diff --git a/config/base/300-operator_v1alpha1_addon_crd.yaml b/config/base/300-operator_v1alpha1_addon_crd.yaml
index 2993993a9..dd2111f7e 100644
--- a/config/base/300-operator_v1alpha1_addon_crd.yaml
+++ b/config/base/300-operator_v1alpha1_addon_crd.yaml
@@ -67,6 +67,18 @@ spec:
               targetNamespace:
                 description: namespace where tekton addons will be installed
                 type: string
+              params:
+                type: array
+                description: list of params to customize installation of components
+                items:
+                  type: object
+                  properties:
+                    name:
+                      description: name of param
+                      type: string
+                    value:
+                      description: value of param
+                      type: string
             type: object
           status:
             description: Status defines the observed state of TektonAddon
diff --git a/config/base/300-operator_v1alpha1_config_crd.yaml b/config/base/300-operator_v1alpha1_config_crd.yaml
index f6ebb3b76..78ae179c6 100644
--- a/config/base/300-operator_v1alpha1_config_crd.yaml
+++ b/config/base/300-operator_v1alpha1_config_crd.yaml
@@ -83,6 +83,22 @@ spec:
                     type: integer
                     default: 1
                 type: object
+              addon:
+                type: object
+                description: defines fields to customize installation of addon components
+                properties:
+                  params:
+                    type: array
+                    description: list of params to customize installation of addon components
+                    items:
+                      type: object
+                      properties:
+                        name:
+                          description: name of param
+                          type: string
+                        value:
+                          description: value of param
+                          type: string
             type: object
           status:
             description: Status defines the observed state of TektonConfig
diff --git a/config/crs/openshift/config/all/operator_v1alpha1_config_cr.yaml b/config/crs/openshift/config/all/operator_v1alpha1_config_cr.yaml
index 1d59a3d87..38432513c 100644
--- a/config/crs/openshift/config/all/operator_v1alpha1_config_cr.yaml
+++ b/config/crs/openshift/config/all/operator_v1alpha1_config_cr.yaml
@@ -19,3 +19,9 @@ metadata:
 spec:
   profile: all
   targetNamespace: openshift-pipelines
+  addon:
+    params:
+    - name: clusterTasks
+      value: "true"
+    - name: pipelineTemplates
+      value: "true"
diff --git a/pkg/apis/operator/v1alpha1/common.go b/pkg/apis/operator/v1alpha1/common.go
index 5d98a7bab..2d816ac98 100644
--- a/pkg/apis/operator/v1alpha1/common.go
+++ b/pkg/apis/operator/v1alpha1/common.go
@@ -97,3 +97,15 @@ type CommonSpec struct {
 func (c *CommonSpec) GetTargetNamespace() string {
 	return c.TargetNamespace
 }
+
+// Param declares an string value to use for the parameter called name.
+type Param struct {
+	Name  string `json:"name"`
+	Value string `json:"value"`
+}
+
+// ParamValue defines a default value and possible values for a param
+type ParamValue struct {
+	Default  string
+	Possible []string
+}
diff --git a/pkg/apis/operator/v1alpha1/tektonaddon_types.go b/pkg/apis/operator/v1alpha1/tektonaddon_types.go
index a9919dbef..2be6b274f 100644
--- a/pkg/apis/operator/v1alpha1/tektonaddon_types.go
+++ b/pkg/apis/operator/v1alpha1/tektonaddon_types.go
@@ -52,6 +52,9 @@ func (tp *TektonAddon) GetStatus() TektonComponentStatus {
 // TektonAddonSpec defines the desired state of TektonAddon
 type TektonAddonSpec struct {
 	CommonSpec `json:",inline"`
+	// The params to customize different components of Addon
+	// +optional
+	Params []Param `json:"params,omitempty"`
 }
 
 // TektonAddonStatus defines the observed state of TektonAddon
diff --git a/pkg/apis/operator/v1alpha1/tektonconfig_types.go b/pkg/apis/operator/v1alpha1/tektonconfig_types.go
index ba8c2abf9..34ce6f72c 100644
--- a/pkg/apis/operator/v1alpha1/tektonconfig_types.go
+++ b/pkg/apis/operator/v1alpha1/tektonconfig_types.go
@@ -67,6 +67,7 @@ type TektonConfigSpec struct {
 	// +optional
 	Pruner     Prune `json:"pruner,omitempty"`
 	CommonSpec `json:",inline"`
+	Addon      Addon `json:"addon,omitempty"`
 }
 
 // TektonConfigStatus defines the observed state of TektonConfig
@@ -89,3 +90,10 @@ type TektonConfigList struct {
 	metav1.ListMeta `json:"metadata,omitempty"`
 	Items           []TektonConfig `json:"items"`
 }
+
+// Addon defines the field to customize Addon component
+type Addon struct {
+	// Params is the list of params passed for Addon customization
+	// +optional
+	Params []Param `json:"params,omitempty"`
+}
diff --git a/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go
index 347e6ac21..cba9a016c 100644
--- a/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go
@@ -24,6 +24,27 @@ import (
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Addon) DeepCopyInto(out *Addon) {
+	*out = *in
+	if in.Params != nil {
+		in, out := &in.Params, &out.Params
+		*out = make([]Param, len(*in))
+		copy(*out, *in)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Addon.
+func (in *Addon) DeepCopy() *Addon {
+	if in == nil {
+		return nil
+	}
+	out := new(Addon)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CommonSpec) DeepCopyInto(out *CommonSpec) {
 	*out = *in
@@ -40,6 +61,43 @@ func (in *CommonSpec) DeepCopy() *CommonSpec {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Param) DeepCopyInto(out *Param) {
+	*out = *in
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Param.
+func (in *Param) DeepCopy() *Param {
+	if in == nil {
+		return nil
+	}
+	out := new(Param)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ParamValue) DeepCopyInto(out *ParamValue) {
+	*out = *in
+	if in.Possible != nil {
+		in, out := &in.Possible, &out.Possible
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParamValue.
+func (in *ParamValue) DeepCopy() *ParamValue {
+	if in == nil {
+		return nil
+	}
+	out := new(ParamValue)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Prune) DeepCopyInto(out *Prune) {
 	*out = *in
@@ -66,7 +124,7 @@ func (in *TektonAddon) DeepCopyInto(out *TektonAddon) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	out.Spec = in.Spec
+	in.Spec.DeepCopyInto(&out.Spec)
 	in.Status.DeepCopyInto(&out.Status)
 	return
 }
@@ -126,6 +184,11 @@ func (in *TektonAddonList) DeepCopyObject() runtime.Object {
 func (in *TektonAddonSpec) DeepCopyInto(out *TektonAddonSpec) {
 	*out = *in
 	out.CommonSpec = in.CommonSpec
+	if in.Params != nil {
+		in, out := &in.Params, &out.Params
+		*out = make([]Param, len(*in))
+		copy(*out, *in)
+	}
 	return
 }
 
@@ -227,6 +290,7 @@ func (in *TektonConfigSpec) DeepCopyInto(out *TektonConfigSpec) {
 	*out = *in
 	in.Pruner.DeepCopyInto(&out.Pruner)
 	out.CommonSpec = in.CommonSpec
+	in.Addon.DeepCopyInto(&out.Addon)
 	return
 }
 
diff --git a/pkg/reconciler/common/install.go b/pkg/reconciler/common/install.go
index 86820f116..5d9504d05 100644
--- a/pkg/reconciler/common/install.go
+++ b/pkg/reconciler/common/install.go
@@ -72,7 +72,7 @@ func Install(ctx context.Context, manifest *mf.Manifest, instance v1alpha1.Tekto
 }
 
 // Uninstall removes all resources
-func Uninstall(ctx context.Context, manifest *mf.Manifest) error {
+func Uninstall(ctx context.Context, manifest *mf.Manifest, instance v1alpha1.TektonComponent) error {
 	if err := manifest.Filter(mf.Not(mf.Any(role, rolebinding))).Delete(); err != nil {
 		return fmt.Errorf("failed to remove non-crd/non-rbac resources: %w", err)
 	}
diff --git a/pkg/reconciler/common/validate.go b/pkg/reconciler/common/validate.go
new file mode 100644
index 000000000..ddfb253a0
--- /dev/null
+++ b/pkg/reconciler/common/validate.go
@@ -0,0 +1,89 @@
+/*
+Copyright 2021 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package common
+
+import (
+	"context"
+	"fmt"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	"knative.dev/pkg/logging"
+)
+
+// ValidateParamsAndSetDefault validates the params and their values with the component params passed
+// If the params from spec is missing some params then this will add them with default values
+// If there is need to check any special conditions, a func can be passed to validate the same params
+// which will be called before setting the default values
+func ValidateParamsAndSetDefault(ctx context.Context, params *[]v1alpha1.Param,
+	componentParams map[string]v1alpha1.ParamValue, validateCond func(params *[]v1alpha1.Param) error) (bool, error) {
+
+	updated := false
+	logger := logging.FromContext(ctx)
+
+	// Validate all params passed are valid and have valid values
+	for _, p := range *params {
+		pv, ok := componentParams[p.Name]
+		if !ok {
+			logger.Error("invalid param: %s")
+			return updated, fmt.Errorf("invalid param : %s", p.Name)
+		}
+		if !isParamValueValid(p.Value, pv.Possible) {
+			msg := fmt.Sprintf("invalid value (%s) for param: %s", p.Value, p.Name)
+			logger.Error(msg)
+			return updated, fmt.Errorf(msg)
+		}
+	}
+
+	err := validateCond(params)
+	if err != nil {
+		return false, err
+	}
+
+	// Parse params and convert in a map
+	specParams := ParseParams(*params)
+
+	// If a param is not passed, add the param with default value
+	for d := range componentParams {
+		_, ok := specParams[d]
+		if !ok {
+			*params = append(*params,
+				v1alpha1.Param{
+					Name:  d,
+					Value: componentParams[d].Default,
+				})
+			updated = true
+		}
+	}
+	return updated, nil
+}
+
+// ParseParams returns the params passed in a map
+func ParseParams(params []v1alpha1.Param) map[string]string {
+	paramsMap := map[string]string{}
+	for _, p := range params {
+		paramsMap[p.Name] = p.Value
+	}
+	return paramsMap
+}
+
+func isParamValueValid(value string, possible []string) bool {
+	for _, v := range possible {
+		if v == value {
+			return true
+		}
+	}
+	return false
+}
diff --git a/pkg/reconciler/kubernetes/tektonconfig/tektonconfig.go b/pkg/reconciler/kubernetes/tektonconfig/tektonconfig.go
index 7ff518062..a27990547 100644
--- a/pkg/reconciler/kubernetes/tektonconfig/tektonconfig.go
+++ b/pkg/reconciler/kubernetes/tektonconfig/tektonconfig.go
@@ -108,6 +108,11 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tc *v1alpha1.TektonConfi
 	}
 
 	if err := r.extension.PreReconcile(ctx, tc); err != nil {
+		// If prereconcile updates the TektonConfig CR, it returns an error
+		// to reconcile
+		if err.Error() == "reconcile" {
+			return err
+		}
 		tc.GetStatus().MarkInstallFailed(err.Error())
 		return err
 	}
diff --git a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
index 33a43fbf3..5f462dc00 100644
--- a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
+++ b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
@@ -82,7 +82,7 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
 		logger.Error("Unable to fetch installed manifest; no cluster-scoped resources will be finalized", err)
 		return nil
 	}
-	if err := common.Uninstall(ctx, manifest); err != nil {
+	if err := common.Uninstall(ctx, manifest, nil); err != nil {
 		logger.Error("Failed to finalize platform resources", err)
 	}
 	return nil
diff --git a/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go b/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go
index 36dc93c67..7f93b56a0 100644
--- a/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go
+++ b/pkg/reconciler/kubernetes/tektonpipeline/tektonpipeline.go
@@ -78,7 +78,7 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
 		logger.Error("Unable to fetch installed manifest; no cluster-scoped resources will be finalized", err)
 		return nil
 	}
-	if err := common.Uninstall(ctx, manifest); err != nil {
+	if err := common.Uninstall(ctx, manifest, nil); err != nil {
 		logger.Error("Failed to finalize platform resources", err)
 	}
 	return nil
diff --git a/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go b/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go
index 046dd8ac6..c561e8f67 100644
--- a/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go
+++ b/pkg/reconciler/kubernetes/tektontrigger/tektontrigger.go
@@ -80,7 +80,7 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
 		logger.Error("Unable to fetch installed manifest; no cluster-scoped resources will be finalized", err)
 		return nil
 	}
-	if err := common.Uninstall(ctx, manifest); err != nil {
+	if err := common.Uninstall(ctx, manifest, nil); err != nil {
 		logger.Error("Failed to finalize platform resources", err)
 	}
 	return nil
diff --git a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
index 1d5179c71..c8c72a2b4 100644
--- a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
+++ b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
@@ -69,8 +69,28 @@ const (
 	providerTypeRedHat    = "redhat"
 	consoleYamlSamples    = "consoleyamlsamples.console.openshift.io"
 	consoleQuickStart     = "consolequickstarts.console.openshift.io"
+
+	// Addon Params
+	clusterTasksParam      = "clusterTasks"
+	pipelineTemplatesParam = "pipelineTemplates"
+)
+
+var (
+	pipeline    mf.Predicate = mf.ByKind("Pipeline")
+	clusterTask mf.Predicate = mf.ByKind("ClusterTask")
 )
 
+var defaultParamValue = v1alpha1.ParamValue{
+	Default:  "true",
+	Possible: []string{"true", "false"},
+}
+
+// AddonParams defines the params defined for Addons with their default value
+var AddonParams = map[string]v1alpha1.ParamValue{
+	clusterTasksParam:      defaultParamValue,
+	pipelineTemplatesParam: defaultParamValue,
+}
+
 // Check that our Reconciler implements controller.Reconciler
 var _ tektonaddonreconciler.Interface = (*Reconciler)(nil)
 var _ tektonaddonreconciler.Finalizer = (*Reconciler)(nil)
@@ -113,7 +133,7 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
 		logger.Error("Unable to fetch installed manifest; no cluster-scoped resources will be finalized", err)
 		return nil
 	}
-	if err := common.Uninstall(ctx, manifest); err != nil {
+	if err := common.Uninstall(ctx, manifest, nil); err != nil {
 		logger.Error("Failed to finalize platform resources", err)
 	}
 	return nil
@@ -138,6 +158,21 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonAddon
 		return nil
 	}
 
+	// If the TektonAddon is created through TektonConfig then validation can be skipped
+	if len(tt.GetOwnerReferences()) == 0 {
+		updated, err := common.ValidateParamsAndSetDefault(ctx, &tt.Spec.Params, AddonParams, ValidateParamsConditions())
+		if err != nil {
+			tt.GetStatus().MarkInstallFailed(err.Error())
+			return err
+		}
+		if updated {
+			_, err := r.operatorClientSet.OperatorV1alpha1().TektonAddons().Update(ctx, tt, metav1.UpdateOptions{})
+			if err != nil {
+				return err
+			}
+		}
+	}
+
 	//find the valid tekton-pipeline installation
 	if _, err := common.PipelineReady(r.pipelineInformer); err != nil {
 		if err.Error() == common.PipelineNotReady {
@@ -145,7 +180,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonAddon
 			// wait for pipeline status to change
 			return fmt.Errorf(common.PipelineNotReady)
 		}
-		// (tektonpipeline.opeator.tekton.dev instance not available yet)
+		// (tektonpipeline.operator.tekton.dev instance not available yet)
 		tt.Status.MarkDependencyMissing("tekton-pipelines does not exist")
 		return err
 	}
@@ -156,7 +191,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonAddon
 			// wait for trigger status to change
 			return fmt.Errorf(common.TriggerNotReady)
 		}
-		// (tektontriggers.opeator.tekton.dev instance not available yet)
+		// (tektontrigger.operator.tekton.dev instance not available yet)
 		tt.Status.MarkDependencyMissing("tekton-triggers does not exist")
 		return err
 	}
@@ -168,7 +203,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonAddon
 	stages := common.Stages{
 		r.appendAddonTarget,
 		r.addonTransform,
-		common.Install,
+		r.filterAndInstall,
 		common.CheckDeployments,
 	}
 	manifest := r.manifest.Append()
@@ -179,13 +214,61 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tt *v1alpha1.TektonAddon
 	stages = common.Stages{
 		r.appendCommunityTarget,
 		r.communityTransform,
-		common.Install,
+		r.checkAndInstall,
 		common.CheckDeployments,
 	}
 	manifest = r.manifest.Append()
 	return stages.Execute(ctx, &manifest, tt)
 }
 
+func (r *Reconciler) checkAndInstall(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) error {
+	ta := comp.(*v1alpha1.TektonAddon)
+	val, ok := findValue(ta.Spec.Params, clusterTasksParam)
+	if !ok {
+		return fmt.Errorf("clusterTasks Param missing in spec")
+	}
+	if val == "true" {
+		return common.Install(ctx, manifest, ta)
+	}
+	return common.Uninstall(ctx, manifest, ta)
+}
+
+func (r *Reconciler) filterAndInstall(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) error {
+	ta := comp.(*v1alpha1.TektonAddon)
+	ptVal, ok := findValue(ta.Spec.Params, pipelineTemplatesParam)
+	if !ok {
+		return fmt.Errorf("pipelineTemplates Param missing in spec")
+	}
+	ctVal, ok := findValue(ta.Spec.Params, clusterTasksParam)
+	if !ok {
+		return fmt.Errorf("clusterTasks Param missing in spec")
+	}
+
+	var installManifest, uninstallManifest mf.Manifest
+	installManifest = *manifest
+
+	if ctVal == "false" {
+		// If clusterTask is false, then install all except clusterTask and pipelinesTemplate
+		// Uninstall clusterTask and pipelinesTemplate, if already exists
+		installManifest = manifest.Filter(mf.Not(mf.Any(clusterTask, pipeline)))
+		uninstallManifest = manifest.Filter(mf.Any(clusterTask, pipeline))
+
+	} else if ptVal == "false" {
+		// If pipelineTemplates is false, then install all except pipelinesTemplate
+		// Uninstall pipelinesTemplate, if already exists
+		installManifest = manifest.Filter(mf.Not(mf.Any(pipeline)))
+		uninstallManifest = manifest.Filter(mf.Any(pipeline))
+	}
+
+	if err := common.Install(ctx, &installManifest, ta); err != nil {
+		return err
+	}
+	if err := common.Uninstall(ctx, &uninstallManifest, ta); err != nil {
+		return err
+	}
+	return nil
+}
+
 // appendAddonTarget mutates the passed manifest by appending one
 // appropriate for the passed TektonComponent
 func (r *Reconciler) appendAddonTarget(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) error {
@@ -370,3 +453,40 @@ func itemInSlice(item string, items []string) bool {
 	}
 	return false
 }
+
+// ValidateParamsConditions validates the param conditions, to be used while
+// validating params and setting default values
+func ValidateParamsConditions() func(params *[]v1alpha1.Param) error {
+	return func(params *[]v1alpha1.Param) error {
+		paramsMap := common.ParseParams(*params)
+
+		// If pipelinesTemplate is true then clusterTask cannot be false
+		// As pipelines created uses this clusterTasks
+		if paramsMap[pipelineTemplatesParam] == "true" && paramsMap[clusterTasksParam] == "false" {
+			return fmt.Errorf("clusterTasks value cannot be false if pipelineTemplates is true")
+		}
+
+		// If user passes clusterTasks as false and pipelinesTemplates param is not passed
+		// then set pipelineTemplatesParam as false, as pipeline template cannot be created
+		// without clusterTask
+		if paramsMap[clusterTasksParam] == "false" {
+			if _, ok := paramsMap[pipelineTemplatesParam]; !ok {
+				*params = append(*params, v1alpha1.Param{
+					Name:  clusterTasksParam,
+					Value: "false",
+				})
+			}
+		}
+
+		return nil
+	}
+}
+
+func findValue(params []v1alpha1.Param, name string) (string, bool) {
+	for _, p := range params {
+		if p.Name == name {
+			return p.Value, true
+		}
+	}
+	return "", false
+}
diff --git a/pkg/reconciler/openshift/tektonconfig/extension.go b/pkg/reconciler/openshift/tektonconfig/extension.go
index 07a78f565..ae1c86e20 100644
--- a/pkg/reconciler/openshift/tektonconfig/extension.go
+++ b/pkg/reconciler/openshift/tektonconfig/extension.go
@@ -18,6 +18,8 @@ package tektonconfig
 
 import (
 	"context"
+	"fmt"
+
 	"github.com/go-logr/zapr"
 	mfc "github.com/manifestival/client-go-client"
 	"go.uber.org/zap"
@@ -28,6 +30,7 @@ import (
 	"github.com/tektoncd/operator/pkg/client/clientset/versioned"
 	operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
 	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/operator/pkg/reconciler/openshift/tektonaddon"
 	"github.com/tektoncd/operator/pkg/reconciler/openshift/tektonconfig/extension"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
@@ -35,7 +38,6 @@ import (
 	"knative.dev/pkg/logging"
 )
 
-// NoPlatform "generates" a NilExtension
 func OpenShiftExtension(ctx context.Context) common.Extension {
 
 	logger := logging.FromContext(ctx)
@@ -67,6 +69,25 @@ func (oe openshiftExtension) Transformers(comp v1alpha1.TektonComponent) []mf.Tr
 	return []mf.Transformer{}
 }
 func (oe openshiftExtension) PreReconcile(ctx context.Context, tc v1alpha1.TektonComponent) error {
+	configInstance := tc.(*v1alpha1.TektonConfig)
+
+	// If profile is all then validates the passed addon params and
+	// add the missing params with their default values
+	if configInstance.Spec.Profile == common.ProfileAll {
+		updated, err := common.ValidateParamsAndSetDefault(ctx, &configInstance.Spec.Addon.Params, tektonaddon.AddonParams,
+			tektonaddon.ValidateParamsConditions())
+		if err != nil {
+			return err
+		}
+		if updated {
+			_, err := oe.operatorClientSet.OperatorV1alpha1().TektonConfigs().Update(ctx, configInstance, metav1.UpdateOptions{})
+			if err != nil {
+				return err
+			}
+			// Returning error just to make reconcile it again so that further code gets updated TektonConfig
+			return fmt.Errorf("reconcile")
+		}
+	}
 
 	r := rbac{
 		kubeClientSet:     oe.kubeClientSet,
diff --git a/pkg/reconciler/openshift/tektonconfig/extension/addon.go b/pkg/reconciler/openshift/tektonconfig/extension/addon.go
index 59b189f93..8772dd5d0 100644
--- a/pkg/reconciler/openshift/tektonconfig/extension/addon.go
+++ b/pkg/reconciler/openshift/tektonconfig/extension/addon.go
@@ -21,6 +21,7 @@ import (
 	"errors"
 	"fmt"
 	"log"
+	"reflect"
 
 	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
 	op "github.com/tektoncd/operator/pkg/client/clientset/versioned/typed/operator/v1alpha1"
@@ -34,7 +35,7 @@ import (
 
 func CreateAddonCR(instance v1alpha1.TektonComponent, client operatorv1alpha1.OperatorV1alpha1Interface) error {
 	configInstance := instance.(*v1alpha1.TektonConfig)
-	if _, err := ensureTektonAddonExists(client.TektonAddons(), configInstance.Spec.TargetNamespace); err != nil {
+	if _, err := ensureTektonAddonExists(client.TektonAddons(), configInstance); err != nil {
 		return errors.New(err.Error())
 	}
 	if _, err := waitForTektonAddonState(client.TektonAddons(), common.AddonResourceName,
@@ -45,9 +46,18 @@ func CreateAddonCR(instance v1alpha1.TektonComponent, client operatorv1alpha1.Op
 	return nil
 }
 
-func ensureTektonAddonExists(clients op.TektonAddonInterface, targetNS string) (*v1alpha1.TektonAddon, error) {
+func ensureTektonAddonExists(clients op.TektonAddonInterface, config *v1alpha1.TektonConfig) (*v1alpha1.TektonAddon, error) {
 	taCR, err := GetAddon(clients, common.AddonResourceName)
 	if err == nil {
+		// If addon params are changed in TektonConfig spec, then only update the Addon CR
+		if !reflect.DeepEqual(config.Spec.Addon.Params, taCR.Spec.Params) {
+			taCR.Spec.Params = config.Spec.Addon.Params
+			updated, err := clients.Update(context.TODO(), taCR, metav1.UpdateOptions{})
+			if err != nil {
+				return nil, err
+			}
+			return updated, nil
+		}
 		return taCR, err
 	}
 	if apierrs.IsNotFound(err) {
@@ -57,8 +67,9 @@ func ensureTektonAddonExists(clients op.TektonAddonInterface, targetNS string) (
 			},
 			Spec: v1alpha1.TektonAddonSpec{
 				CommonSpec: v1alpha1.CommonSpec{
-					TargetNamespace: targetNS,
+					TargetNamespace: config.Spec.TargetNamespace,
 				},
+				Params: config.Spec.Addon.Params,
 			},
 		}
 		return clients.Create(context.TODO(), taCR, metav1.CreateOptions{})
diff --git a/pkg/reconciler/openshift/tektonconfig/rbac.go b/pkg/reconciler/openshift/tektonconfig/rbac.go
index 012caa776..0fdded9c4 100644
--- a/pkg/reconciler/openshift/tektonconfig/rbac.go
+++ b/pkg/reconciler/openshift/tektonconfig/rbac.go
@@ -40,6 +40,7 @@ const (
 	serviceCABundleConfigMap = "config-service-cabundle"
 	trustedCABundleConfigMap = "config-trusted-cabundle"
 	namespaceIgnorePattern   = "^(openshift|kube)-"
+	clusterInterceptors      = "openshift-pipelines-clusterinterceptors"
 )
 
 type rbac struct {
@@ -92,6 +93,10 @@ func (r *rbac) createResources(ctx context.Context) error {
 		if err := r.ensureRoleBindings(ctx, sa); err != nil {
 			return err
 		}
+
+		if err := r.ensureClusterRoleBindings(ctx, sa); err != nil {
+			return err
+		}
 	}
 
 	return nil
@@ -383,8 +388,7 @@ func (r *rbac) createRoleBinding(ctx context.Context, sa *corev1.ServiceAccount)
 	rbacClient := r.kubeClientSet.RbacV1()
 
 	logger.Info("finding clusterrole edit")
-	_, err := rbacClient.ClusterRoles().Get(ctx, "edit", metav1.GetOptions{})
-	if err != nil {
+	if _, err := rbacClient.ClusterRoles().Get(ctx, "edit", metav1.GetOptions{}); err != nil {
 		logger.Error(err, "getting clusterRole 'edit' failed")
 		return err
 	}
@@ -399,9 +403,118 @@ func (r *rbac) createRoleBinding(ctx context.Context, sa *corev1.ServiceAccount)
 		Subjects: []rbacv1.Subject{{Kind: rbacv1.ServiceAccountKind, Name: sa.Name, Namespace: sa.Namespace}},
 	}
 
-	_, err = rbacClient.RoleBindings(sa.Namespace).Create(ctx, rb, metav1.CreateOptions{})
-	if err != nil {
+	if _, err := rbacClient.RoleBindings(sa.Namespace).Create(ctx, rb, metav1.CreateOptions{}); err != nil {
 		logger.Error(err, "creation of 'edit' rolebinding failed, in Namespace", sa.GetNamespace())
+		return err
+	}
+	return nil
+}
+
+func (r *rbac) ensureClusterRoleBindings(ctx context.Context, sa *corev1.ServiceAccount) error {
+	logger := logging.FromContext(ctx)
+
+	rbacClient := r.kubeClientSet.RbacV1()
+	logger.Info("finding cluster-role ", clusterInterceptors)
+	if _, err := rbacClient.ClusterRoles().Get(ctx, clusterInterceptors, metav1.GetOptions{}); errors.IsNotFound(err) {
+		return r.createClusterRole(ctx)
+	}
+
+	logger.Info("finding cluster-role-binding ", clusterInterceptors)
+
+	viewCRB, err := rbacClient.ClusterRoleBindings().Get(ctx, clusterInterceptors, metav1.GetOptions{})
+
+	if err == nil {
+		logger.Infof("found clusterrolebinding %s", viewCRB.Name)
+		return r.updateClusterRoleBinding(ctx, viewCRB, sa)
+	}
+
+	if errors.IsNotFound(err) {
+		return r.createClusterRoleBinding(ctx, sa)
 	}
+
 	return err
 }
+
+func (r *rbac) updateClusterRoleBinding(ctx context.Context, rb *rbacv1.ClusterRoleBinding, sa *corev1.ServiceAccount) error {
+	logger := logging.FromContext(ctx)
+
+	subject := rbacv1.Subject{Kind: rbacv1.ServiceAccountKind, Name: sa.Name, Namespace: sa.Namespace}
+
+	hasSubject := hasSubject(rb.Subjects, subject)
+	if !hasSubject {
+		rb.Subjects = append(rb.Subjects, subject)
+	}
+
+	ownerRef := rb.GetOwnerReferences()
+	if len(ownerRef) == 0 {
+		rb.SetOwnerReferences([]metav1.OwnerReference{r.ownerRef})
+	}
+
+	if hasSubject && (len(ownerRef) != 0) {
+		logger.Info("clusterrolebinding is up to date", "action", "none")
+		return nil
+	}
+
+	logger.Info("update existing clusterrolebinding ", clusterInterceptors)
+	rbacClient := r.kubeClientSet.RbacV1()
+
+	if _, err := rbacClient.ClusterRoleBindings().Update(ctx, rb, metav1.UpdateOptions{}); err != nil {
+		logger.Error(err, "failed to update "+clusterInterceptors+" crb")
+		return err
+	}
+	logger.Info("successfully updated ", clusterInterceptors)
+	return nil
+}
+
+func (r *rbac) createClusterRoleBinding(ctx context.Context, sa *corev1.ServiceAccount) error {
+	logger := logging.FromContext(ctx)
+
+	logger.Info("create new clusterrolebinding ", clusterInterceptors)
+	rbacClient := r.kubeClientSet.RbacV1()
+
+	logger.Info("finding clusterrole ", clusterInterceptors)
+	if _, err := rbacClient.ClusterRoles().Get(ctx, clusterInterceptors, metav1.GetOptions{}); err != nil {
+		logger.Error(err, " getting clusterRole "+clusterInterceptors+" failed")
+		return err
+	}
+
+	crb := &rbacv1.ClusterRoleBinding{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:            clusterInterceptors,
+			OwnerReferences: []metav1.OwnerReference{r.ownerRef},
+		},
+		RoleRef:  rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "ClusterRole", Name: clusterInterceptors},
+		Subjects: []rbacv1.Subject{{Kind: rbacv1.ServiceAccountKind, Name: sa.Name, Namespace: sa.Namespace}},
+	}
+
+	if _, err := rbacClient.ClusterRoleBindings().Create(ctx, crb, metav1.CreateOptions{}); err != nil {
+		logger.Error(err, " creation of "+clusterInterceptors+" failed")
+		return err
+	}
+	return nil
+}
+
+func (r *rbac) createClusterRole(ctx context.Context) error {
+	logger := logging.FromContext(ctx)
+
+	logger.Info("create new clusterrole ", clusterInterceptors)
+	rbacClient := r.kubeClientSet.RbacV1()
+
+	cr := &rbacv1.ClusterRole{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:            clusterInterceptors,
+			OwnerReferences: []metav1.OwnerReference{r.ownerRef},
+		},
+		Rules: []rbacv1.PolicyRule{{
+			APIGroups: []string{"triggers.tekton.dev"},
+			Resources: []string{"clusterinterceptors"},
+			Verbs:     []string{"get", "list", "watch"},
+		}},
+	}
+
+	if _, err := rbacClient.ClusterRoles().Create(ctx, cr, metav1.CreateOptions{}); err != nil {
+		logger.Error(err, "creation of "+clusterInterceptors+" clusterrole failed")
+		return err
+	}
+	return nil
+}


Test patch:
diff --git a/pkg/reconciler/common/install_test.go b/pkg/reconciler/common/install_test.go
index 74af55b3e..b57be27e8 100644
--- a/pkg/reconciler/common/install_test.go
+++ b/pkg/reconciler/common/install_test.go
@@ -156,7 +156,7 @@ func TestUninstall(t *testing.T) {
 		t.Fatalf("Failed to generate manifest: %v", err)
 	}
 
-	if err := Uninstall(context.TODO(), &manifest); err != nil {
+	if err := Uninstall(context.TODO(), &manifest, nil); err != nil {
 		t.Fatalf("Uninstall() = %v, want no error", err)
 	}
 
diff --git a/pkg/reconciler/common/validate_test.go b/pkg/reconciler/common/validate_test.go
new file mode 100644
index 000000000..969b06e7b
--- /dev/null
+++ b/pkg/reconciler/common/validate_test.go
@@ -0,0 +1,83 @@
+/*
+Copyright 2021 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package common
+
+import (
+	"context"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	"gotest.tools/assert"
+	"testing"
+)
+
+func nullFunc() func(params *[]v1alpha1.Param) error {
+	return func(params *[]v1alpha1.Param) error {
+		return nil
+	}
+}
+
+func TestValidateParamsAndSetDefault(t *testing.T) {
+
+	componentParams := map[string]v1alpha1.ParamValue{
+		"valid": v1alpha1.ParamValue{
+			Default:  "param",
+			Possible: []string{"param", "param1"},
+		},
+		"newParam": v1alpha1.ParamValue{
+			Default:  "newValue",
+			Possible: []string{"newValue", "newValue1"},
+		},
+	}
+
+	t.Run("Invalid Param", func(t *testing.T) {
+		params := []v1alpha1.Param{
+			{Name: "foo", Value: "bar"},
+		}
+		_, err := ValidateParamsAndSetDefault(context.TODO(), &params, componentParams, nullFunc())
+		assert.Error(t, err, "invalid param : foo")
+	})
+
+	t.Run("Invalid Param Value", func(t *testing.T) {
+		params := []v1alpha1.Param{
+			{Name: "valid", Value: "bar"},
+		}
+		_, err := ValidateParamsAndSetDefault(context.TODO(), &params, componentParams, nullFunc())
+		assert.Error(t, err, "invalid value (bar) for param: valid")
+	})
+
+	t.Run("All params are defined so no error", func(t *testing.T) {
+		params := []v1alpha1.Param{
+			{Name: "valid", Value: "param1"},
+			{Name: "newParam", Value: "newValue"},
+		}
+		updated, err := ValidateParamsAndSetDefault(context.TODO(), &params, componentParams, nullFunc())
+		assert.NilError(t, err)
+		assert.Equal(t, updated, false)
+	})
+
+	t.Run("Some params are missing", func(t *testing.T) {
+		params := []v1alpha1.Param{
+			{Name: "valid", Value: "param1"},
+		}
+		updated, err := ValidateParamsAndSetDefault(context.TODO(), &params, componentParams, nullFunc())
+		assert.NilError(t, err)
+		// since some params are added to spec, updated should be true
+		assert.Equal(t, updated, true)
+		// missing params will be added with default value
+		assert.Equal(t, params[1].Name, "newParam")
+		assert.Equal(t, params[1].Value, "newValue")
+	})
+}
diff --git a/test/e2e/common/tektonconfigdeployment_test.go b/test/e2e/common/tektonconfigdeployment_test.go
index d611c48dc..592ac94a0 100644
--- a/test/e2e/common/tektonconfigdeployment_test.go
+++ b/test/e2e/common/tektonconfigdeployment_test.go
@@ -19,13 +19,17 @@ limitations under the License.
 package common
 
 import (
+	"context"
 	"os"
+	"reflect"
 	"testing"
 
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
 	"github.com/tektoncd/operator/pkg/reconciler/common"
 	"github.com/tektoncd/operator/test/client"
 	"github.com/tektoncd/operator/test/resources"
 	"github.com/tektoncd/operator/test/utils"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 // TestTektonPipelinesDeployment verifies the TektonPipelines creation, deployment recreation, and TektonPipelines deletion.
@@ -37,16 +41,24 @@ func TestTektonConfigDeployment(t *testing.T) {
 		Namespace:    "tekton-operator",
 	}
 
-	if os.Getenv("TARGET") == "openshift" {
+	platform := os.Getenv("TARGET")
+
+	if platform == "openshift" {
 		crNames.Namespace = "openshift-operators"
 	}
 
 	utils.CleanupOnInterrupt(func() { utils.TearDownConfig(clients, crNames.TektonConfig) })
 	defer utils.TearDownPipeline(clients, crNames.TektonConfig)
 
+	var (
+		tc  *v1alpha1.TektonConfig
+		err error
+	)
+
 	// Create a TektonConfig
 	t.Run("create-config", func(t *testing.T) {
-		if _, err := resources.EnsureTektonConfigExists(clients.KubeClientSet, clients.TektonConfig(), crNames); err != nil {
+		tc, err = resources.EnsureTektonConfigExists(clients.KubeClientSet, clients.TektonConfig(), crNames)
+		if err != nil {
 			t.Fatalf("TektonConfig %q failed to create: %v", crNames.TektonConfig, err)
 		}
 	})
@@ -56,10 +68,14 @@ func TestTektonConfigDeployment(t *testing.T) {
 		resources.AssertTektonConfigCRReadyStatus(t, clients, crNames)
 	})
 
-	if os.Getenv("TARGET") == "openshift" {
+	if platform == "openshift" {
 		runRbacTest(t, clients)
 	}
 
+	if platform == "openshift" && tc.Spec.Profile == common.ProfileAll {
+		runAddonTest(t, clients, tc)
+	}
+
 	// Delete the TektonConfig CR instance to see if all resources will be removed
 	t.Run("delete-config", func(t *testing.T) {
 		resources.AssertTektonConfigCRReadyStatus(t, clients, crNames)
@@ -67,6 +83,29 @@ func TestTektonConfigDeployment(t *testing.T) {
 	})
 }
 
+func runAddonTest(t *testing.T, clients *utils.Clients, tc *v1alpha1.TektonConfig) {
+
+	var (
+		addon *v1alpha1.TektonAddon
+		err   error
+	)
+
+	// Make sure TektonAddon is created
+	t.Run("ensure-addon-is-created", func(t *testing.T) {
+		addon, err = clients.Operator.TektonAddons().Get(context.TODO(), common.AddonResourceName, metav1.GetOptions{})
+		if err != nil {
+			t.Fatalf("failed to get TektonAddon CR: %s : %v", common.AddonResourceName, err)
+		}
+	})
+
+	// Check if number of params passed in TektonConfig would be passed in TektonAddons
+	t.Run("check-addon-params", func(t *testing.T) {
+		if !reflect.DeepEqual(tc.Spec.Addon.Params, addon.Spec.Params) {
+			t.Fatalf("Addon params in TektonConfig not equal to TektonAddon params")
+		}
+	})
+}
+
 func runRbacTest(t *testing.T, clients *utils.Clients) {
 
 	// Test whether the supporting rbac resources are created for existing namespace and
diff --git a/test/e2e/common/tektonpipelinedeployment_test.go b/test/e2e/common/tektonpipelinedeployment_test.go
index a777b6ba0..b6c31e177 100644
--- a/test/e2e/common/tektonpipelinedeployment_test.go
+++ b/test/e2e/common/tektonpipelinedeployment_test.go
@@ -19,6 +19,7 @@ limitations under the License.
 package common
 
 import (
+	"os"
 	"testing"
 
 	"github.com/tektoncd/operator/test/utils"
@@ -37,6 +38,10 @@ func TestTektonPipelinesDeployment(t *testing.T) {
 		TargetNamespace: "tekton-pipelines",
 	}
 
+	if os.Getenv("TARGET") == "openshift" {
+		crNames.TargetNamespace = "openshift-pipelines"
+	}
+
 	utils.CleanupOnInterrupt(func() { utils.TearDownPipeline(clients, crNames.TektonPipeline) })
 	defer utils.TearDownPipeline(clients, crNames.TektonPipeline)
 
diff --git a/test/e2e/common/tektontriggerdeployment_test.go b/test/e2e/common/tektontriggerdeployment_test.go
index f2cff4d68..59c6afb30 100644
--- a/test/e2e/common/tektontriggerdeployment_test.go
+++ b/test/e2e/common/tektontriggerdeployment_test.go
@@ -19,6 +19,7 @@ limitations under the License.
 package common
 
 import (
+	"os"
 	"testing"
 
 	"github.com/tektoncd/operator/test/utils"
@@ -38,6 +39,10 @@ func TestTektonTriggersDeployment(t *testing.T) {
 		TargetNamespace: "tekton-pipelines",
 	}
 
+	if os.Getenv("TARGET") == "openshift" {
+		crNames.TargetNamespace = "openshift-pipelines"
+	}
+
 	utils.CleanupOnInterrupt(func() { utils.TearDownPipeline(clients, crNames.TektonPipeline) })
 	defer utils.TearDownPipeline(clients, crNames.TektonPipeline)
 
diff --git a/test/e2e/openshift/tektonaddondeployment_test.go b/test/e2e/openshift/tektonaddondeployment_test.go
index f3dffd74a..4539b0a60 100644
--- a/test/e2e/openshift/tektonaddondeployment_test.go
+++ b/test/e2e/openshift/tektonaddondeployment_test.go
@@ -19,6 +19,7 @@ limitations under the License.
 package openshift
 
 import (
+	"os"
 	"testing"
 
 	"github.com/tektoncd/operator/test/utils"
@@ -40,6 +41,10 @@ func TestTektonAddonsDeployment(t *testing.T) {
 		TargetNamespace: "tekton-pipelines",
 	}
 
+	if os.Getenv("TARGET") == "openshift" {
+		crNames.TargetNamespace = "openshift-pipelines"
+	}
+
 	utils.CleanupOnInterrupt(func() { utils.TearDownPipeline(clients, crNames.TektonPipeline) })
 	defer utils.TearDownPipeline(clients, crNames.TektonPipeline)