Repository: tektoncd/operator
Pull request #800 (2022-05-23 12:23:11)

Replace pac cronjob service account to work in openshift-pipelines ns
Signed-off-by: Shivam Mukhade <smukhade@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

<!--
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
```
-->


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/800#issuecomment-1134656381" 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/release-v0.55.x/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/openshift/tektonaddon/pipelinesascode.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/800/pull-tekton-operator-go-coverage/1529074804521439232/artifacts/line-cov.html#file0) | 21.2% | 19.4% | -1.8
[pkg/reconciler/openshift/tektonaddon/transformer.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/800/pull-tekton-operator-go-coverage/1529074804521439232/artifacts/line-cov.html#file1) | 57.0% | 59.8% | 2.8

nikhil-thomas: ✅ lgtm
tekton-robot: @sm43: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-build-tests | 6f53518701d5f87cc6e32c3e8c037d68e58d1e7e | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/800/pull-tekton-operator-build-tests/1529074804521439235/) | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://tekton-releases.appspot.com/pr/tektoncd_operator/800). [Your PR dashboard](https://prow.tekton.dev/pr/sm43).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
nikhil-thomas: /lgtm

Patch:
diff --git a/cmd/openshift/operator/kodata/tekton-addon/addons/06-pipelines-as-code/pac-sa.yaml b/cmd/openshift/operator/kodata/tekton-addon/addons/06-pipelines-as-code/pac-sa.yaml
new file mode 100644
index 000000000..e33d47221
--- /dev/null
+++ b/cmd/openshift/operator/kodata/tekton-addon/addons/06-pipelines-as-code/pac-sa.yaml
@@ -0,0 +1,37 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: pipelines-as-code-cleanup-job
+  namespace: pipelines-as-code
+  labels:
+    app.kubernetes.io/instance: default
+    app.kubernetes.io/part-of: pipelines-as-code
+---
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: pipelines-as-code-cleanup-job
+  namespace: pipelines-as-code
+  labels:
+    app.kubernetes.io/instance: default
+    app.kubernetes.io/part-of: pipelines-as-code
+rules:
+  - apiGroups: ["tekton.dev"]
+    resources: ["taskruns"]
+    verbs: ["get", "list", "delete"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: pipelines-as-code-cleanup-job
+  namespace: pipelines-as-code
+  labels:
+    app.kubernetes.io/instance: default
+    app.kubernetes.io/part-of: pipelines-as-code
+subjects:
+  - kind: ServiceAccount
+    name: pipelines-as-code-cleanup-job
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: pipelines-as-code-cleanup-job
\ No newline at end of file
diff --git a/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go b/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go
index cef12ca19..59428250e 100644
--- a/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go
+++ b/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go
@@ -28,6 +28,8 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+const cjServiceAccount = "pipelines-as-code-cleanup-job"
+
 var pacLS = metav1.LabelSelector{
 	MatchLabels: map[string]string{
 		v1alpha1.InstallerSetType: PACInstallerSet,
@@ -70,6 +72,10 @@ func (r *Reconciler) ensurePAC(ctx context.Context, ta *v1alpha1.TektonAddon) er
 		return err
 	}
 
+	if err := applyAddons(&pacManifest, "06-pipelines-as-code"); err != nil {
+		return err
+	}
+
 	// installerSet adds it's owner as namespace's owner
 	// so deleting tekton addon deletes target namespace too
 	// to skip it we filter out namespace
@@ -82,6 +88,7 @@ func (r *Reconciler) ensurePAC(ctx context.Context, ta *v1alpha1.TektonAddon) er
 		tfs = append(tfs, replacePACTriggerTemplateImages(triggerTemplateSteps))
 	}
 
+	tfs = append(tfs, replaceCronjobServiceAccount(cjServiceAccount))
 	if err := r.addonTransform(ctx, &pacManifest, ta, tfs...); err != nil {
 		return err
 	}
diff --git a/pkg/reconciler/openshift/tektonaddon/transformer.go b/pkg/reconciler/openshift/tektonaddon/transformer.go
index a5f13b71c..4b43f4af2 100644
--- a/pkg/reconciler/openshift/tektonaddon/transformer.go
+++ b/pkg/reconciler/openshift/tektonaddon/transformer.go
@@ -20,8 +20,10 @@ import (
 	"bytes"
 	"encoding/json"
 	"fmt"
+
 	pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	triggersv1beta1 "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1"
+	v1 "k8s.io/api/batch/v1"
 
 	mf "github.com/manifestival/manifestival"
 	console "github.com/openshift/api/console/v1"
@@ -247,3 +249,28 @@ func replacePACTriggerTemplateImages(stepsImages map[string]string) mf.Transform
 		return nil
 	}
 }
+
+func replaceCronjobServiceAccount(serviceAccount string) mf.Transformer {
+	return func(u *unstructured.Unstructured) error {
+		if u.GetKind() != "CronJob" {
+			return nil
+		}
+
+		cj := &v1.CronJob{}
+		err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cj)
+		if err != nil {
+			return err
+		}
+
+		cj.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName = serviceAccount
+		cj.Spec.JobTemplate.Spec.Template.Spec.DeprecatedServiceAccount = serviceAccount
+
+		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cj)
+		if err != nil {
+			return err
+		}
+		u.SetUnstructuredContent(unstrObj)
+
+		return nil
+	}
+}


Test patch:
diff --git a/pkg/reconciler/openshift/tektonaddon/testdata/test-pac-cj.yaml b/pkg/reconciler/openshift/tektonaddon/testdata/test-pac-cj.yaml
new file mode 100644
index 000000000..b7c63fcd5
--- /dev/null
+++ b/pkg/reconciler/openshift/tektonaddon/testdata/test-pac-cj.yaml
@@ -0,0 +1,49 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: pipelines-as-code-pr-cleanup
+  namespace: pipelines-as-code
+  labels:
+    app.kubernetes.io/version: "devel"
+    app.kubernetes.io/part-of: pipelines-as-code
+spec:
+  concurrencyPolicy: Replace
+  failedJobsHistoryLimit: 1
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+            - command:
+                - /bin/bash
+                - -c
+                - test -e /etc/config/max-keep-days && export MAX_DAY_KEEP=$(cat /etc/config/max-keep-days);for pr in $(kubectl get taskruns -l app.kubernetes.io/managed-by=pipelines-as-code -o json | python3 -c "import
+                  os, sys, datetime, json;jeez=json.load(sys.stdin);res=[ i['metadata']['name']
+                  for i in jeez['items'] if datetime.datetime.now() > datetime.datetime.strptime(i['metadata']['creationTimestamp'],
+                  '%Y-%m-%dT%H:%M:%SZ') + datetime.timedelta(days=int(os.environ.get('MAX_DAY_KEEP', 1))) ];print(' '.join(res))");do
+                  kubectl delete taskrun ${pr};done
+              image: quay.io/openshift/origin-cli:4.8
+              imagePullPolicy: IfNotPresent
+              name: cleanup
+              terminationMessagePath: /dev/termination-log
+              terminationMessagePolicy: File
+              volumeMounts:
+                - name: config-volume
+                  mountPath: /etc/config
+              env:
+                - name: MAX_DAY_KEEP
+                  value: "1"
+          dnsPolicy: ClusterFirst
+          restartPolicy: Never
+          schedulerName: default-scheduler
+          serviceAccount: pipeline
+          serviceAccountName: pipeline
+          terminationGracePeriodSeconds: 30
+          volumes:
+            - name: config-volume
+              configMap:
+                name: pipelines-as-code
+                optional: true
+  schedule: "0 * * * *"
+  successfulJobsHistoryLimit: 1
+  suspend: false
\ No newline at end of file
diff --git a/pkg/reconciler/openshift/tektonaddon/transformer_test.go b/pkg/reconciler/openshift/tektonaddon/transformer_test.go
index 5115648bc..ae5f24628 100644
--- a/pkg/reconciler/openshift/tektonaddon/transformer_test.go
+++ b/pkg/reconciler/openshift/tektonaddon/transformer_test.go
@@ -19,8 +19,6 @@ package tektonaddon
 import (
 	"bytes"
 	"encoding/json"
-	pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
-	triggersv1beta1 "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1"
 	"os"
 	"path"
 	"testing"
@@ -28,8 +26,11 @@ import (
 	"github.com/google/go-cmp/cmp"
 	mf "github.com/manifestival/manifestival"
 	console "github.com/openshift/api/console/v1"
+	pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	"github.com/tektoncd/pipeline/test/diff"
+	triggersv1beta1 "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1"
 	"gotest.tools/v3/assert"
+	v1 "k8s.io/api/batch/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
@@ -120,3 +121,20 @@ func TestReplacePACTriggerTemplateImages(t *testing.T) {
 		}
 	}
 }
+
+func TestReplaceCronjonServiceAccount(t *testing.T) {
+	testData := path.Join("testdata", "test-pac-cj.yaml")
+	manifest, err := mf.ManifestFrom(mf.Recursive(testData))
+	assert.NilError(t, err)
+
+	serviceAccount := "test-abc"
+	transformedManifest, err := manifest.Transform(replaceCronjobServiceAccount(serviceAccount))
+	assert.NilError(t, err)
+
+	cj := &v1.CronJob{}
+	err = runtime.DefaultUnstructuredConverter.FromUnstructured(transformedManifest.Resources()[0].Object, cj)
+	assert.NilError(t, err)
+
+	assert.Equal(t, cj.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName, serviceAccount)
+	assert.Equal(t, cj.Spec.JobTemplate.Spec.Template.Spec.DeprecatedServiceAccount, serviceAccount)
+}