Repository: tektoncd/operator
Pull request #617 (2022-02-07 12:08:41)

[openshift] add maven clustertask
This adds maven clustertask using maven image from the internal registry
and removes it from the community tasks

Signed-off-by: Pradeep Kumar <pradkuma@redhat.com>

# Changes

<!-- 🎉🎉🎉 Thank you for the PR!!! 🎉🎉🎉 -->

<!-- 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:

- [ ] Includes [tests](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if functionality changed/added)
- [ ] Includes [docs](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if user facing)
- [ ] 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

<i>This is openshift specific change. </i>
With this PR we remove fetching maven task from community task url's which mostly use gcr based images.
Now we have maven clustertask in our addon/clustertasks folder.
This clustertask uses `image-registry.openshift-image-registry.svc:5000/openshift/openjdk-11-rhel8:1.0` image for maven goals from our internal image registry.

<!--
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
```
-->


tekton-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **vdemeester**
You can assign the PR to them by writing `/assign @vdemeester` in a comment when ready.

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

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

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

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":["vdemeester"]} -->
pradeepitm12: cc: @nikhil-thomas @savitaashture 

Patch:
diff --git a/Makefile b/Makefile
index 4b7c302f3..42d357401 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ KO = $(or ${KO_BIN},${KO_BIN},$(BIN)/ko)
 TEKTON_PIPELINE_VERSION ?= latest
 TEKTON_TRIGGERS_VERSION ?= latest
 TEKTON_DASHBOARD_VERSION ?= latest
-TEKTON_RESULTS_VERSION ?= v0.3.1 # latest returns an older version hence hard coding to v0.3.1 for now (tektoncd/results#138)
+TEKTON_RESULTS_VERSION ?= v0.4.0 # latest returns an older version hence hard coding to v0.3.1 for now (tektoncd/results#138)
 PAC_VERSION ?= 0.5.2
 
 $(BIN)/ko: PACKAGE=github.com/google/ko/cmd/ko
diff --git a/cmd/openshift/operator/kodata/tekton-addon/addons/02-clustertasks/maven/maven-task.yaml b/cmd/openshift/operator/kodata/tekton-addon/addons/02-clustertasks/maven/maven-task.yaml
new file mode 100644
index 000000000..c7c2f3bd2
--- /dev/null
+++ b/cmd/openshift/operator/kodata/tekton-addon/addons/02-clustertasks/maven/maven-task.yaml
@@ -0,0 +1,148 @@
+apiVersion: tekton.dev/v1beta1
+kind: ClusterTask
+metadata:
+  name: maven
+  labels:
+    app.kubernetes.io/version: "0.2"
+  annotations:
+    tekton.dev/pipelines.minVersion: "0.12.1"
+    tekton.dev/tags: build-tool
+spec:
+  description: >-
+    This Task can be used to run a Maven build.
+
+  workspaces:
+    - name: source
+      description: The workspace consisting of maven project.
+    - name: maven-settings
+      description: >-
+        The workspace consisting of the custom maven settings
+        provided by the user.
+  params:
+    - name: MAVEN_IMAGE
+      type: string
+      description: Maven base image
+      default: image-registry.openshift-image-registry.svc:5000/openshift/openjdk-11-rhel8:1.0
+    - name: GOALS
+      description: maven goals to run
+      type: array
+      default:
+        - "package"
+    - name: MAVEN_MIRROR_URL
+      description: The Maven repository mirror url
+      type: string
+      default: ""
+    - name: SERVER_USER
+      description: The username for the server
+      type: string
+      default: ""
+    - name: SERVER_PASSWORD
+      description: The password for the server
+      type: string
+      default: ""
+    - name: PROXY_USER
+      description: The username for the proxy server
+      type: string
+      default: ""
+    - name: PROXY_PASSWORD
+      description: The password for the proxy server
+      type: string
+      default: ""
+    - name: PROXY_PORT
+      description: Port number for the proxy server
+      type: string
+      default: ""
+    - name: PROXY_HOST
+      description: Proxy server Host
+      type: string
+      default: ""
+    - name: PROXY_NON_PROXY_HOSTS
+      description: Non proxy server host
+      type: string
+      default: ""
+    - name: PROXY_PROTOCOL
+      description: Protocol for the proxy ie http or https
+      type: string
+      default: "http"
+    - name: CONTEXT_DIR
+      type: string
+      description: >-
+        The context directory within the repository for sources on
+        which we want to execute maven goals.
+      default: "."
+  steps:
+    - name: mvn-settings
+      image: registry.access.redhat.com/ubi8/ubi-minimal:8.2
+      script: |
+        #!/usr/bin/env bash
+
+        [[ -f $(workspaces.maven-settings.path)/settings.xml ]] && \
+        echo 'using existing $(workspaces.maven-settings.path)/settings.xml' && exit 0
+
+        cat > $(workspaces.maven-settings.path)/settings.xml <<EOF
+        <settings>
+          <servers>
+            <!-- The servers added here are generated from environment variables. Don't change. -->
+            <!-- ### SERVER's USER INFO from ENV ### -->
+          </servers>
+          <mirrors>
+            <!-- The mirrors added here are generated from environment variables. Don't change. -->
+            <!-- ### mirrors from ENV ### -->
+          </mirrors>
+          <proxies>
+            <!-- The proxies added here are generated from environment variables. Don't change. -->
+            <!-- ### HTTP proxy from ENV ### -->
+          </proxies>
+        </settings>
+        EOF
+
+        xml=""
+        if [ -n "$(params.PROXY_HOST)" -a -n "$(params.PROXY_PORT)" ]; then
+          xml="<proxy>\
+            <id>genproxy</id>\
+            <active>true</active>\
+            <protocol>$(params.PROXY_PROTOCOL)</protocol>\
+            <host>$(params.PROXY_HOST)</host>\
+            <port>$(params.PROXY_PORT)</port>"
+          if [ -n "$(params.PROXY_USER)" -a -n "$(params.PROXY_PASSWORD)" ]; then
+            xml="$xml\
+                <username>$(params.PROXY_USER)</username>\
+                <password>$(params.PROXY_PASSWORD)</password>"
+          fi
+          if [ -n "$(params.PROXY_NON_PROXY_HOSTS)" ]; then
+            xml="$xml\
+                <nonProxyHosts>$(params.PROXY_NON_PROXY_HOSTS)</nonProxyHosts>"
+          fi
+          xml="$xml\
+              </proxy>"
+          sed -i "s|<!-- ### HTTP proxy from ENV ### -->|$xml|" $(workspaces.maven-settings.path)/settings.xml
+        fi
+
+        if [ -n "$(params.SERVER_USER)" -a -n "$(params.SERVER_PASSWORD)" ]; then
+          xml="<server>\
+            <id>serverid</id>"
+          xml="$xml\
+                <username>$(params.SERVER_USER)</username>\
+                <password>$(params.SERVER_PASSWORD)</password>"
+          xml="$xml\
+              </server>"
+          sed -i "s|<!-- ### SERVER's USER INFO from ENV ### -->|$xml|" $(workspaces.maven-settings.path)/settings.xml
+        fi
+
+        if [ -n "$(params.MAVEN_MIRROR_URL)" ]; then
+          xml="    <mirror>\
+            <id>mirror.default</id>\
+            <url>$(params.MAVEN_MIRROR_URL)</url>\
+            <mirrorOf>central</mirrorOf>\
+          </mirror>"
+          sed -i "s|<!-- ### mirrors from ENV ### -->|$xml|" $(workspaces.maven-settings.path)/settings.xml
+        fi
+
+    - name: mvn-goals
+      image: $(params.MAVEN_IMAGE)
+      workingDir: $(workspaces.source.path)/$(params.CONTEXT_DIR)
+      command: ["/usr/bin/mvn"]
+      args:
+        - -s
+        - $(workspaces.maven-settings.path)/settings.xml
+        - "$(params.GOALS)"
diff --git a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
index 8ddc8e023..2e2273602 100644
--- a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
+++ b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
@@ -27,6 +27,7 @@ import (
 	pipelineinformer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
 	tektondashboardreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektondashboard"
 	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset"
 	"github.com/tektoncd/operator/pkg/reconciler/shared/hash"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -62,7 +63,14 @@ type Reconciler struct {
 var _ tektondashboardreconciler.Interface = (*Reconciler)(nil)
 var _ tektondashboardreconciler.Finalizer = (*Reconciler)(nil)
 
-var watchedResourceName = "dashboard"
+var (
+	ls = metav1.LabelSelector{
+		MatchLabels: map[string]string{
+			v1alpha1.CreatedByKey:     createdByValue,
+			v1alpha1.InstallerSetType: v1alpha1.DashboardResourceName,
+		},
+	}
+)
 
 const createdByValue = "TektonDashboard"
 
@@ -86,11 +94,6 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
 		return err
 	}
 
-	ls := metav1.LabelSelector{
-		MatchLabels: map[string]string{
-			v1alpha1.CreatedByKey: createdByValue,
-		},
-	}
 	labelSelector, err := common.LabelSelector(ls)
 	if err != nil {
 		return err
@@ -119,9 +122,9 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb
 
 	logger.Infow("Reconciling TektonDashboards", "status", td.Status)
 
-	if td.GetName() != watchedResourceName {
+	if td.GetName() != v1alpha1.DashboardResourceName {
 		msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s",
-			watchedResourceName,
+			v1alpha1.DashboardResourceName,
 			td.GetName(),
 		)
 		logger.Error(msg)
@@ -152,11 +155,16 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb
 	// Mark PreReconcile Complete
 	td.Status.MarkPreReconcilerComplete()
 
-	// Check if an tekton installer set already exists, if not then create
-	existingInstallerSet := td.Status.GetTektonInstallerSet()
+	// Check if an tektoninstallerset already exists, if not then create
+	labelSelector, err := common.LabelSelector(ls)
+	if err != nil {
+		return err
+	}
+	existingInstallerSet, err := tektoninstallerset.CurrentInstallerSetName(ctx, r.operatorClientSet, labelSelector)
+	if err != nil {
+		return err
+	}
 	if existingInstallerSet == "" {
-		td.Status.MarkInstallerSetNotAvailable("Dashboard Installer Set Not Available")
-
 		createdIs, err := r.createInstallerSet(ctx, td)
 		if err != nil {
 			return err
@@ -181,7 +189,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashb
 	}
 
 	installerSetTargetNamespace := installedTIS.Annotations[v1alpha1.TargetNamespaceKey]
-	installerSetReleaseVersion := installedTIS.Annotations[v1alpha1.ReleaseVersionKey]
+	installerSetReleaseVersion := installedTIS.Labels[v1alpha1.ReleaseVersionKey]
 
 	// Check if TargetNamespace of existing TektonInstallerSet is same as expected
 	// Check if Release Version in TektonInstallerSet is same as expected
@@ -344,7 +352,7 @@ func (r *Reconciler) createInstallerSet(ctx context.Context, td *v1alpha1.Tekton
 	}
 
 	// create installer set
-	tis := makeInstallerSet(td, manifest, specHash, r.operatorVersion)
+	tis := r.makeInstallerSet(td, manifest, specHash)
 	createdIs, err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
 		Create(ctx, tis, metav1.CreateOptions{})
 	if err != nil {
@@ -353,16 +361,17 @@ func (r *Reconciler) createInstallerSet(ctx context.Context, td *v1alpha1.Tekton
 	return createdIs, nil
 }
 
-func makeInstallerSet(td *v1alpha1.TektonDashboard, manifest mf.Manifest, tdSpecHash, releaseVersion string) *v1alpha1.TektonInstallerSet {
+func (r *Reconciler) makeInstallerSet(td *v1alpha1.TektonDashboard, manifest mf.Manifest, tdSpecHash string) *v1alpha1.TektonInstallerSet {
 	ownerRef := *metav1.NewControllerRef(td, td.GetGroupVersionKind())
 	return &v1alpha1.TektonInstallerSet{
 		ObjectMeta: metav1.ObjectMeta{
 			GenerateName: fmt.Sprintf("%s-", v1alpha1.DashboardResourceName),
 			Labels: map[string]string{
-				v1alpha1.CreatedByKey: createdByValue,
+				v1alpha1.CreatedByKey:      createdByValue,
+				v1alpha1.InstallerSetType:  v1alpha1.DashboardResourceName,
+				v1alpha1.ReleaseVersionKey: r.operatorVersion,
 			},
 			Annotations: map[string]string{
-				v1alpha1.ReleaseVersionKey:  releaseVersion,
 				v1alpha1.TargetNamespaceKey: td.Spec.TargetNamespace,
 				v1alpha1.LastAppliedHashKey: tdSpecHash,
 			},
diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/install.go b/pkg/reconciler/kubernetes/tektoninstallerset/install.go
index 52ae315dc..a9098a554 100644
--- a/pkg/reconciler/kubernetes/tektoninstallerset/install.go
+++ b/pkg/reconciler/kubernetes/tektoninstallerset/install.go
@@ -71,15 +71,44 @@ type installer struct {
 	Manifest mf.Manifest
 }
 
-func (i *installer) EnsureCRDs() error {
-	if err := i.Manifest.Filter(mf.Any(mf.CRDs)).Apply(); err != nil {
+func ensureResources(mani *mf.Manifest) error {
+	freshCreate := true
+	// check if all resources in a given set of resources exists
+	ok, err := allResourcesExists(mani)
+	if err != nil {
+		if !apierrs.IsNotFound(err) {
+			return err
+		}
+	}
+	// if error == NotFound error or !ok
+	// then Apply all resources
+	// if ok, that means the reosource already exists
+	// but this reconcile could be an modification eg: concig-defaults change
+	// set freshCreate flag to false, and then Apply all
+	// so that we can skip (break) RECONCILE_AGAIN loop path
+	if ok {
+		freshCreate = false
+	}
+
+	if err := mani.Apply(); err != nil {
 		return err
 	}
+	// on err == nil after Apply() return RECONCILE_AGAIN
+	// if freshCreate == true return RECONCILE_AGAIN
+	// this ensures freshly created resources are in place before proceeding to next stages of reconciler
+	if freshCreate {
+		return v1alpha1.RECONCILE_AGAIN_ERR
+	}
 	return nil
 }
 
+func (i *installer) EnsureCRDs() error {
+	resourceList := i.Manifest.Filter(mf.Any(mf.CRDs))
+	return ensureResources(&resourceList)
+}
+
 func (i *installer) EnsureClusterScopedResources() error {
-	if err := i.Manifest.Filter(
+	resourceList := i.Manifest.Filter(
 		mf.Any(
 			namespacePred,
 			clusterRolePred,
@@ -92,14 +121,12 @@ func (i *installer) EnsureClusterScopedResources() error {
 			consoleQuickStartPred,
 			ConsoleYAMLSamplePred,
 			securityContextConstraints,
-		)).Apply(); err != nil {
-		return err
-	}
-	return nil
+		))
+	return ensureResources(&resourceList)
 }
 
 func (i *installer) EnsureNamespaceScopedResources() error {
-	if err := i.Manifest.Filter(
+	resourceList := i.Manifest.Filter(
 		mf.Any(
 			serviceAccountPred,
 			clusterRoleBindingPred,
@@ -114,10 +141,10 @@ func (i *installer) EnsureNamespaceScopedResources() error {
 			eventListenerPred,
 			triggerBindingPred,
 			triggerTemplatePred,
-		)).Apply(); err != nil {
-		return err
-	}
-	return nil
+			servicePred,
+			routePred,
+		))
+	return ensureResources(&resourceList)
 }
 
 func (i *installer) EnsureDeploymentResources() error {
@@ -128,13 +155,6 @@ func (i *installer) EnsureDeploymentResources() error {
 		}
 	}
 
-	if err := i.Manifest.Filter(
-		mf.Any(
-			servicePred,
-			routePred,
-		)).Apply(); err != nil {
-		return err
-	}
 	return nil
 }
 
@@ -202,7 +222,11 @@ func (i *installer) updateDeployment(existing *unstructured.Unstructured, existi
 	}
 	existing.SetUnstructuredContent(unstrObj)
 
-	return i.Manifest.Client.Update(existing)
+	err = i.Manifest.Client.Update(existing)
+	if err != nil {
+		return v1alpha1.RECONCILE_AGAIN_ERR
+	}
+	return err
 }
 
 func (i *installer) ensureDeployment(expected *unstructured.Unstructured) error {
@@ -213,7 +237,11 @@ func (i *installer) ensureDeployment(expected *unstructured.Unstructured) error
 
 		// If deployment doesn't exist, then create new
 		if apierrs.IsNotFound(err) {
-			return i.createDeployment(expected)
+			errInner := i.createDeployment(expected)
+			if errInner == nil {
+				return v1alpha1.RECONCILE_AGAIN_ERR
+			}
+			return errInner
 		}
 		return err
 	}
@@ -348,3 +376,25 @@ func isDeploymentAvailable(d *appsv1.Deployment) bool {
 	}
 	return false
 }
+
+func allResourcesExists(m *mf.Manifest) (bool, error) {
+	c := m.Client
+	for _, item := range m.Resources() {
+		ok, err := resourceExists(c, &item)
+		if err != nil {
+			return false, err
+		}
+		if !ok {
+			return false, nil
+		}
+	}
+	return true, nil
+}
+
+func resourceExists(c mf.Client, u *unstructured.Unstructured) (bool, error) {
+	_, err := c.Get(u)
+	if err != nil {
+		return false, err
+	}
+	return true, nil
+}
diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/tektoninstallerset.go b/pkg/reconciler/kubernetes/tektoninstallerset/tektoninstallerset.go
index 373de1be4..1c2b256fc 100644
--- a/pkg/reconciler/kubernetes/tektoninstallerset/tektoninstallerset.go
+++ b/pkg/reconciler/kubernetes/tektoninstallerset/tektoninstallerset.go
@@ -57,7 +57,8 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, installerSet *v1alpha1.Te
 	// Delete all resources except CRDs and Namespace as they are own by owner of
 	// TektonInstallerSet
 	// They will be deleted when the component CR is deleted
-	err = deleteManifests.Filter(mf.Not(mf.Any(namespacePred, mf.CRDs))).Delete()
+	deleteManifests = deleteManifests.Filter(mf.Not(mf.Any(namespacePred, mf.CRDs)))
+	err = deleteManifests.Delete(mf.PropagationPolicy(v1.DeletePropagationForeground))
 	if err != nil {
 		logger.Error("failed to delete resources")
 		return err
@@ -107,7 +108,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, installerSet *v1alpha1.T
 	err = installer.EnsureCRDs()
 	if err != nil {
 		installerSet.Status.MarkCRDsInstallationFailed(err.Error())
-		return err
+		return r.handleError(err, installerSet)
 	}
 
 	// Update Status for CRD condition
@@ -117,7 +118,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, installerSet *v1alpha1.T
 	err = installer.EnsureClusterScopedResources()
 	if err != nil {
 		installerSet.Status.MarkClustersScopedInstallationFailed(err.Error())
-		return err
+		return r.handleError(err, installerSet)
 	}
 
 	// Update Status for ClustersScope Condition
@@ -127,7 +128,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, installerSet *v1alpha1.T
 	err = installer.EnsureNamespaceScopedResources()
 	if err != nil {
 		installerSet.Status.MarkNamespaceScopedInstallationFailed(err.Error())
-		return err
+		return r.handleError(err, installerSet)
 	}
 
 	// Update Status for NamespaceScope Condition
@@ -137,7 +138,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, installerSet *v1alpha1.T
 	err = installer.EnsureDeploymentResources()
 	if err != nil {
 		installerSet.Status.MarkDeploymentsAvailableFailed(err.Error())
-		return err
+		return r.handleError(err, installerSet)
 	}
 
 	// Update Status for Deployment Resources
@@ -179,3 +180,11 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, installerSet *v1alpha1.T
 
 	return nil
 }
+
+func (r *Reconciler) handleError(err error, installerSet *v1alpha1.TektonInstallerSet) error {
+	if err == v1alpha1.RECONCILE_AGAIN_ERR {
+		r.enqueueAfter(installerSet, 10*time.Second)
+		return nil
+	}
+	return err
+}
diff --git a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
index 0c12746e9..8c01072ef 100644
--- a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
+++ b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
@@ -72,7 +72,6 @@ var _ tektonaddonreconciler.Finalizer = (*Reconciler)(nil)
 
 var communityResourceURLs = []string{
 	"https://raw.githubusercontent.com/tektoncd/catalog/master/task/jib-maven/0.4/jib-maven.yaml",
-	"https://raw.githubusercontent.com/tektoncd/catalog/master/task/maven/0.2/maven.yaml",
 	"https://raw.githubusercontent.com/tektoncd/catalog/master/task/helm-upgrade-from-source/0.3/helm-upgrade-from-source.yaml",
 	"https://raw.githubusercontent.com/tektoncd/catalog/master/task/helm-upgrade-from-repo/0.2/helm-upgrade-from-repo.yaml",
 	"https://raw.githubusercontent.com/tektoncd/catalog/master/task/trigger-jenkins-job/0.1/trigger-jenkins-job.yaml",


Test patch:
diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go b/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go
index 5fd96fdf8..b29581b67 100644
--- a/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go
+++ b/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go
@@ -23,6 +23,8 @@ import (
 	"github.com/google/go-cmp/cmp"
 	mf "github.com/manifestival/manifestival"
 	"github.com/manifestival/manifestival/fake"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	"gotest.tools/v3/assert"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
@@ -54,6 +56,7 @@ type fakeClient struct {
 	getErr         error
 	createErr      error
 	resourcesExist bool
+	gets           []unstructured.Unstructured
 	creates        []unstructured.Unstructured
 	deletes        []unstructured.Unstructured
 }
@@ -61,7 +64,12 @@ type fakeClient struct {
 func (f *fakeClient) Get(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
 	var resource *unstructured.Unstructured
 	if f.resourcesExist {
-		resource = &unstructured.Unstructured{}
+		for _, item := range f.gets {
+			if obj.GetKind() == item.GetKind() && obj.GetName() == item.GetName() {
+				return &item, nil
+			}
+		}
+
 	}
 	return resource, f.getErr
 }
@@ -97,7 +105,7 @@ func clusterScopedResource(apiVersion, kind, name string) unstructured.Unstructu
 }
 
 func TestInstaller(t *testing.T) {
-
+	crd.SetDeletionTimestamp(&metav1.Time{})
 	in := []unstructured.Unstructured{namespace, deployment, clusterRole, role,
 		roleBinding, clusterRoleBinding, serviceAccount, crd, validatingWebhook, mutatingWebhook, configMap, service, hpa, secret}
 
@@ -140,7 +148,7 @@ func TestInstaller(t *testing.T) {
 	client.creates = []unstructured.Unstructured{}
 
 	want = []unstructured.Unstructured{serviceAccount, clusterRoleBinding, role,
-		roleBinding, configMap, secret, hpa}
+		roleBinding, configMap, secret, hpa, service}
 
 	err = i.EnsureNamespaceScopedResources()
 	if err != nil {
@@ -159,17 +167,20 @@ func TestInstaller(t *testing.T) {
 		Resource: "Deployment",
 	}, "test-deployment")
 
-	want = []unstructured.Unstructured{deployment, service}
-
 	err = i.EnsureDeploymentResources()
-	if err != nil {
-		t.Fatal("Unexpected Error while installing resources: ", err)
-	}
+	assert.Error(t, err, v1alpha1.RECONCILE_AGAIN_ERR.Error())
 
+	want = []unstructured.Unstructured{deployment}
 	if len(want) != len(client.creates) {
 		t.Fatalf("Unexpected creates: %s", fmt.Sprintf("(-got, +want): %s", cmp.Diff(client.creates, want)))
 	}
 
+	client.resourcesExist = true
+	client.gets = []unstructured.Unstructured{deployment}
+	err = i.EnsureDeploymentResources()
+	if err != nil {
+		t.Fatal("Unexpected Error while installing resources: ", err)
+	}
 }
 
 var (
diff --git a/test/config.sh b/test/config.sh
index a5474913e..b164c555d 100644
--- a/test/config.sh
+++ b/test/config.sh
@@ -1,4 +1,5 @@
 export TEKTON_PIPELINE_VERSION=latest
 export TEKTON_TRIGGERS_VERSION=latest
-export TEKTON_RESULTS_VERSION=v0.3.1
+export TEKTON_RESULTS_VERSION=v0.4.0
 export TEKTON_DASHBOARD_VERSION=latest
+export PAC_VERSION=0.5.2
diff --git a/test/e2e/kubernetes/tektondashboarddeployment_test.go b/test/e2e/kubernetes/tektondashboarddeployment_test.go
index f6bd0aee5..ad26ec092 100644
--- a/test/e2e/kubernetes/tektondashboarddeployment_test.go
+++ b/test/e2e/kubernetes/tektondashboarddeployment_test.go
@@ -74,6 +74,11 @@ func TestTektonDashboardsDeployment(t *testing.T) {
 		resources.AssertTektonDashboardCRReadyStatus(t, clients, crNames)
 	})
 
+	// Test if TektonInstallerSets are created.
+	t.Run("verify-dashboard-installersets", func(t *testing.T) {
+		resources.AssertDashboardInstallerSets(t, clients)
+	})
+
 	// Delete the TektonDashboard CR instance to see if all resources will be removed
 	t.Run("delete-dashboard", func(t *testing.T) {
 		resources.AssertTektonDashboardCRReadyStatus(t, clients, crNames)
diff --git a/test/resources/tektonaddons.go b/test/resources/tektonaddons.go
index a522e8286..1854d3a73 100644
--- a/test/resources/tektonaddons.go
+++ b/test/resources/tektonaddons.go
@@ -96,15 +96,15 @@ func AssertTektonAddonCRReadyStatus(t *testing.T, clients *utils.Clients, names
 
 // AssertTektonInstallerSets verifies if the TektonInstallerSets are created.
 func AssertTektonInstallerSets(t *testing.T, clients *utils.Clients) {
-	assertInstallerSetsForAddon(t, clients, tektonaddon.ClusterTaskInstallerSet)
-	assertInstallerSetsForAddon(t, clients, tektonaddon.VersionedClusterTaskInstallerSet)
-	assertInstallerSetsForAddon(t, clients, tektonaddon.PipelinesTemplateInstallerSet)
-	assertInstallerSetsForAddon(t, clients, tektonaddon.TriggersResourcesInstallerSet)
-	assertInstallerSetsForAddon(t, clients, tektonaddon.ConsoleCLIInstallerSet)
-	assertInstallerSetsForAddon(t, clients, tektonaddon.MiscellaneousResourcesInstallerSet)
+	assertInstallerSets(t, clients, tektonaddon.ClusterTaskInstallerSet)
+	assertInstallerSets(t, clients, tektonaddon.VersionedClusterTaskInstallerSet)
+	assertInstallerSets(t, clients, tektonaddon.PipelinesTemplateInstallerSet)
+	assertInstallerSets(t, clients, tektonaddon.TriggersResourcesInstallerSet)
+	assertInstallerSets(t, clients, tektonaddon.ConsoleCLIInstallerSet)
+	assertInstallerSets(t, clients, tektonaddon.MiscellaneousResourcesInstallerSet)
 }
 
-func assertInstallerSetsForAddon(t *testing.T, clients *utils.Clients, component string) {
+func assertInstallerSets(t *testing.T, clients *utils.Clients, component string) {
 	ls := metav1.LabelSelector{
 		MatchLabels: map[string]string{
 			v1alpha1.InstallerSetType: component,
@@ -114,13 +114,13 @@ func assertInstallerSetsForAddon(t *testing.T, clients *utils.Clients, component
 	if err != nil {
 		t.Fatal(err)
 	}
-	clusterTaskIS, err := clients.TektonInstallerSet().List(context.TODO(), metav1.ListOptions{
+	installerSets, err := clients.TektonInstallerSet().List(context.TODO(), metav1.ListOptions{
 		LabelSelector: labelSelector,
 	})
 	if err != nil {
 		t.Fatalf("failed to get TektonInstallerSet for %s : %v", component, err)
 	}
-	if len(clusterTaskIS.Items) > 1 {
+	if len(installerSets.Items) > 1 {
 		t.Fatalf("multiple installer sets for %s TektonInstallerSet", component)
 	}
 }
diff --git a/test/resources/tektondashboards.go b/test/resources/tektondashboards.go
index 85bf4bd91..50c6507e8 100644
--- a/test/resources/tektondashboards.go
+++ b/test/resources/tektondashboards.go
@@ -83,6 +83,11 @@ func IsTektonDashboardReady(s *v1alpha1.TektonDashboard, err error) (bool, error
 	return s.Status.IsReady(), err
 }
 
+// AssertTektonInstallerSets verifies if the TektonInstallerSets are created.
+func AssertDashboardInstallerSets(t *testing.T, clients *utils.Clients) {
+	assertInstallerSets(t, clients, v1alpha1.DashboardResourceName)
+}
+
 // AssertTektonDashboardCRReadyStatus verifies if the TektonDashboard reaches the READY status.
 func AssertTektonDashboardCRReadyStatus(t *testing.T, clients *utils.Clients, names utils.ResourceNames) {
 	if _, err := WaitForTektonDashboardState(clients.TektonDashboard(), names.TektonDashboard,