Repository: tektoncd/operator
Pull request #674 (2022-03-11 13:29:13)

Add new transformer for triggers on openshift
This will add one new transformer to update the args of a
deployment container

This transformer will be used in trigger reconciler to
update the value of two args in triggers controller
to make the default security context false and
enable the el events

Add tests

# 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

```release-note
Add new tranformer for triggers on openshift
```



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 **savitaashture**
You can assign the PR to them by writing `/assign @savitaashture` 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":["savitaashture"]} -->
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/tektontrigger/extension.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/674/pull-tekton-operator-go-coverage/1502275501530550272/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/tektontrigger/transformers.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/674/pull-tekton-operator-go-coverage/1502275501530550272/artifacts/line-cov.html#file2) | Do not exist | 87.0% | 

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/tektontrigger/extension.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/674/pull-tekton-operator-go-coverage/1502275753100709888/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/tektontrigger/transformers.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/674/pull-tekton-operator-go-coverage/1502275753100709888/artifacts/line-cov.html#file2) | Do not exist | 87.0% | 

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

This pull-request has been approved by: *<a href="https://github.com/tektoncd/operator/pull/674#pullrequestreview-907232320" title="Approved">vdemeester</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)~~ [vdemeester]

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: /cc @savitaashture 
tekton-robot: @sm43: ![cat image](https://cdn2.thecatapi.com/images/LzOC8HsUz.jpg)

<details>

In response to [this](https://github.com/tektoncd/operator/pull/674#issuecomment-1065136687):

>/lgtm
>/meow


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.
</details>

Patch:
diff --git a/Makefile b/Makefile
index 82ef8013e..03fd328e5 100644
--- a/Makefile
+++ b/Makefile
@@ -68,6 +68,7 @@ ifeq ($(TARGET), openshift)
 	rm -rf ./cmd/$(TARGET)/operator/kodata/tekton-chains
 	rm -rf ./cmd/$(TARGET)/operator/kodata/tekton-hub
 	rm -rf ./cmd/$(TARGET)/operator/kodata/tekton-addon/pipelines-as-code
+	rm -rf ./cmd/$(TARGET)/operator/kodata/tekton-addon/addons/02-clustertasks/source_external/
 else
 	rm -rf ./cmd/$(TARGET)/operator/kodata/tekton*
 endif
diff --git a/pkg/reconciler/common/transformers.go b/pkg/reconciler/common/transformers.go
index 4d3c84a4e..aac037d60 100644
--- a/pkg/reconciler/common/transformers.go
+++ b/pkg/reconciler/common/transformers.go
@@ -240,7 +240,7 @@ func replaceContainerImages(containers []corev1.Container, images map[string]str
 
 func replaceContainersArgsImage(container *corev1.Container, images map[string]string) {
 	for a, arg := range container.Args {
-		if argVal, hasArg := splitsByEqual(arg); hasArg {
+		if argVal, hasArg := SplitsByEqual(arg); hasArg {
 			argument := formKey(ArgPrefix, argVal[0])
 			if url, exist := images[argument]; exist {
 				container.Args[a] = argVal[0] + "=" + url
@@ -264,7 +264,7 @@ func formKey(prefix, arg string) string {
 	return strings.ReplaceAll(argument, "-", "_")
 }
 
-func splitsByEqual(arg string) ([]string, bool) {
+func SplitsByEqual(arg string) ([]string, bool) {
 	values := strings.Split(arg, "=")
 	if len(values) == 2 {
 		return values, true
diff --git a/pkg/reconciler/openshift/tektontrigger/extension.go b/pkg/reconciler/openshift/tektontrigger/extension.go
index 74d28fc81..31e5d498a 100644
--- a/pkg/reconciler/openshift/tektontrigger/extension.go
+++ b/pkg/reconciler/openshift/tektontrigger/extension.go
@@ -43,6 +43,8 @@ func (oe openshiftExtension) Transformers(comp v1alpha1.TektonComponent) []mf.Tr
 		occommon.RemoveRunAsUser(),
 		occommon.RemoveRunAsGroup(),
 		occommon.ApplyCABundles,
+		replaceDeploymentArgs("-el-security-context", "false"),
+		replaceDeploymentArgs("-el-events", "enable"),
 	}
 }
 func (oe openshiftExtension) PreReconcile(ctx context.Context, tc v1alpha1.TektonComponent) error {
diff --git a/pkg/reconciler/openshift/tektontrigger/transformers.go b/pkg/reconciler/openshift/tektontrigger/transformers.go
new file mode 100644
index 000000000..a2bc5bf2b
--- /dev/null
+++ b/pkg/reconciler/openshift/tektontrigger/transformers.go
@@ -0,0 +1,69 @@
+/*
+Copyright 2022 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 tektontrigger
+
+import (
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	appsv1 "k8s.io/api/apps/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+// replace the value of a deployment arg provided argToReplace and value
+func replaceDeploymentArgs(argToReplace, value string) mf.Transformer {
+	return func(u *unstructured.Unstructured) error {
+		if u.GetKind() != "Deployment" {
+			return nil
+		}
+
+		d := &appsv1.Deployment{}
+		err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, d)
+		if err != nil {
+			return err
+		}
+
+		containers := d.Spec.Template.Spec.Containers
+		for _, container := range containers {
+			if len(container.Args) == 0 {
+				continue
+			}
+			for j, arg := range container.Args {
+				// for scenario when key and value are in single arg e.g. "key=value"
+				if argVal, hasArg := common.SplitsByEqual(arg); hasArg {
+					if argVal[0] == argToReplace {
+						container.Args[j] = argVal[0] + "=" + value
+					}
+					continue
+				}
+				// for scenario, when key and value are in different args, eg. "key","value"
+				if arg == argToReplace {
+					container.Args[j+1] = value
+				}
+			}
+
+		}
+
+		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(d)
+		if err != nil {
+			return err
+		}
+		u.SetUnstructuredContent(unstrObj)
+
+		return nil
+	}
+}


Test patch:
diff --git a/pkg/reconciler/openshift/tektontrigger/testdata/test-replace-image.yaml b/pkg/reconciler/openshift/tektontrigger/testdata/test-replace-image.yaml
new file mode 100644
index 000000000..0d6b605a4
--- /dev/null
+++ b/pkg/reconciler/openshift/tektontrigger/testdata/test-replace-image.yaml
@@ -0,0 +1,55 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: controller
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      run: test
+  template:
+    metadata:
+      labels:
+        run: test
+    spec:
+      containers:
+        - image: busybox
+          name: controller-deployment
+          args: [
+            "-logtostderr",
+            "-stderrthreshold", "INFO",
+            "-el-image", "ko://github.com/tektoncd/triggers/cmd/eventlistenersink",
+            "-el-port", "8080",
+            "-el-security-context=true",
+            "-el-events", "disable",
+            "-el-readtimeout", "5",
+            "-el-writetimeout", "40",
+            "-el-idletimeout", "120",
+            "-el-timeouthandler", "30",
+          ]
+        - image: busybox
+          name: sidecar
+          args: [
+            "-logtostderr",
+            "-stderrthreshold", "INFO",
+            "-el-image", "ko://github.com/tektoncd/triggers/cmd/eventlistenersink",
+            "-el-port", "8080",
+            "-el-events", "disable",
+            "-el-readtimeout", "5",
+            "-el-writetimeout", "40",
+            "-el-idletimeout", "120",
+            "-el-timeouthandler", "30",
+          ]
+        - image: busybox
+          name: webhook-deployment
+          args: [
+            "-logtostderr",
+            "-stderrthreshold", "INFO",
+            "-el-image", "ko://github.com/tektoncd/triggers/cmd/eventlistenersink",
+            "-el-port", "8080",
+            "-el-events", "disable",
+            "-el-readtimeout", "5",
+            "-el-writetimeout", "40",
+            "-el-idletimeout", "120",
+            "-el-timeouthandler", "30",
+          ]
diff --git a/pkg/reconciler/openshift/tektontrigger/testdata/test-replace-kind.yaml b/pkg/reconciler/openshift/tektontrigger/testdata/test-replace-kind.yaml
new file mode 100644
index 000000000..304962282
--- /dev/null
+++ b/pkg/reconciler/openshift/tektontrigger/testdata/test-replace-kind.yaml
@@ -0,0 +1,12 @@
+apiVersion: tekton.dev/v1alpha1
+kind: Task
+metadata:
+  name: echo-hello-world
+spec:
+  steps:
+  - name: echo
+    image: ubuntu
+    command:
+    - echo
+    args:
+    - "hello world"
diff --git a/pkg/reconciler/openshift/tektontrigger/transformers_test.go b/pkg/reconciler/openshift/tektontrigger/transformers_test.go
new file mode 100644
index 000000000..30d1db291
--- /dev/null
+++ b/pkg/reconciler/openshift/tektontrigger/transformers_test.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2022 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 tektontrigger
+
+import (
+	"path"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/pipeline/test/diff"
+	appsv1 "k8s.io/api/apps/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+func TestReplaceImages(t *testing.T) {
+	t.Run("ignore non deployment", func(t *testing.T) {
+		testData := path.Join("testdata", "test-replace-kind.yaml")
+		expected, _ := mf.ManifestFrom(mf.Recursive(testData))
+
+		manifest, err := mf.ManifestFrom(mf.Recursive(testData))
+		if err != nil {
+			t.Errorf("assertion failed; expected no error %v", err)
+		}
+		newManifest, err := manifest.Transform(replaceDeploymentArgs("--test", "value"))
+		if err != nil {
+			t.Errorf("assertion failed; expected no error %v", err)
+		}
+
+		if d := cmp.Diff(expected.Resources(), newManifest.Resources()); d != "" {
+			t.Errorf("failed to update deployment %s", diff.PrintWantGot(d))
+		}
+	})
+
+	t.Run("replace containers args", func(t *testing.T) {
+		testData := path.Join("testdata", "test-replace-image.yaml")
+		manifest, err := mf.ManifestFrom(mf.Recursive(testData))
+		if err != nil {
+			t.Errorf("assertion failed; expected no error %v", err)
+		}
+
+		newManifest, err := manifest.Transform(
+			replaceDeploymentArgs("-el-security-context", "false"),
+			replaceDeploymentArgs("-el-events", "enable"),
+		)
+		if err != nil {
+			t.Errorf("assertion failed; expected no error %v", err)
+		}
+		assertDeployContainerArgsValue(t, newManifest.Resources(), "-el-security-context", "false")
+		assertDeployContainerArgsValue(t, newManifest.Resources(), "-el-events", "enable")
+	})
+}
+
+func assertDeployContainerArgsValue(t *testing.T, resources []unstructured.Unstructured, arg string, value string) {
+	t.Helper()
+
+	for _, resource := range resources {
+		deployment := &appsv1.Deployment{}
+		err := runtime.DefaultUnstructuredConverter.FromUnstructured(resource.Object, deployment)
+		if err != nil {
+			t.Errorf("failed to load deployment yaml")
+		}
+		containers := deployment.Spec.Template.Spec.Containers
+
+		for _, container := range containers {
+			if len(container.Args) == 0 {
+				continue
+			}
+
+			for a, argument := range container.Args {
+				if argVal, hasArg := common.SplitsByEqual(arg); hasArg {
+					if argVal[0] == argument && argVal[1] == value {
+						t.Errorf("not equal: expected %v, got %v", value, argVal[1])
+					}
+					continue
+				}
+
+				if argument == arg && container.Args[a+1] != value {
+					t.Errorf("not equal: expected %v, got %v", value, container.Args[a+1])
+				}
+			}
+		}
+	}
+}