Repository: tektoncd/pipeline (Go)

Issue:
`TaskRun` unconditionally patches `Pods` once `SidecarsReady`
# Expected Behavior

I would expect this to elide the patch once the label is in place:
https://github.com/tektoncd/pipeline/blob/76e40b5a7b11262bfaa96ae31f28db2009002115/pkg/pod/entrypoint.go#L208-L215

This is a problem because each client operation eats away at the client-side rate limit.

# Actual Behavior

Every reconciliation after `SidecarsReady` issues a `PATCH` to the pod, despite the fact that the pod is passed in 🙃 




Discussion:

Patch:
diff --git a/pkg/pod/entrypoint.go b/pkg/pod/entrypoint.go
index d1aaa30a06d..02c35a3ad3a 100644
--- a/pkg/pod/entrypoint.go
+++ b/pkg/pod/entrypoint.go
@@ -213,6 +213,11 @@ func init() {
 // UpdateReady updates the Pod's annotations to signal the first step to start
 // by projecting the ready annotation via the Downward API.
 func UpdateReady(ctx context.Context, kubeclient kubernetes.Interface, pod corev1.Pod) error {
+	// Don't PATCH if the annotation is already Ready.
+	if pod.Annotations[readyAnnotation] == readyAnnotationValue {
+		return nil
+	}
+
 	// PATCH the Pod's annotations to replace the ready annotation with the
 	// "READY" value, to signal the first step to start.
 	_, err := kubeclient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, types.JSONPatchType, replaceReadyPatchBytes, metav1.PatchOptions{})


Test patch:
diff --git a/pkg/pod/entrypoint_test.go b/pkg/pod/entrypoint_test.go
index e895f58146f..6eff144c262 100644
--- a/pkg/pod/entrypoint_test.go
+++ b/pkg/pod/entrypoint_test.go
@@ -27,7 +27,9 @@ import (
 	"github.com/tektoncd/pipeline/test/diff"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
 	fakek8s "k8s.io/client-go/kubernetes/fake"
+	k8stesting "k8s.io/client-go/testing"
 )
 
 var volumeMount = corev1.VolumeMount{
@@ -353,6 +355,7 @@ func TestUpdateReady(t *testing.T) {
 		pod             corev1.Pod
 		wantAnnotations map[string]string
 		wantErr         bool
+		wantPatch       bool // Whether we expect PATCH to be called on the pod.
 	}{{
 		desc: "Pod without any annotations fails",
 		pod: corev1.Pod{
@@ -361,7 +364,8 @@ func TestUpdateReady(t *testing.T) {
 				Annotations: nil,
 			},
 		},
-		wantErr: true, // Nothing to replace.
+		wantErr:   true, // Nothing to replace.
+		wantPatch: true,
 	}, {
 		desc: "Pod without ready annotation adds it",
 		pod: corev1.Pod{
@@ -376,6 +380,7 @@ func TestUpdateReady(t *testing.T) {
 			"something":     "else",
 			readyAnnotation: "READY",
 		},
+		wantPatch: true,
 	}, {
 		desc: "Pod with empty annotation value has it replaced",
 		pod: corev1.Pod{
@@ -391,6 +396,7 @@ func TestUpdateReady(t *testing.T) {
 			"something":     "else",
 			readyAnnotation: readyAnnotationValue,
 		},
+		wantPatch: true,
 	}, {
 		desc: "Pod with other annotation value has it replaced",
 		pod: corev1.Pod{
@@ -406,16 +412,45 @@ func TestUpdateReady(t *testing.T) {
 			"something":     "else",
 			readyAnnotation: readyAnnotationValue,
 		},
+		wantPatch: true,
+	}, {
+		desc: "Pod with READY annotation already set isn't patched",
+		pod: corev1.Pod{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "pod",
+				Annotations: map[string]string{
+					"something":     "else",
+					readyAnnotation: readyAnnotationValue,
+				},
+			},
+		},
+		wantAnnotations: map[string]string{
+			"something":     "else",
+			readyAnnotation: readyAnnotationValue,
+		},
+		wantPatch: false,
 	}} {
 		t.Run(c.desc, func(t *testing.T) {
 			ctx := context.Background()
 			ctx, cancel := context.WithCancel(ctx)
 			defer cancel()
 			kubeclient := fakek8s.NewSimpleClientset(&c.pod)
+			patchCalled := false
+			kubeclient.PrependReactor("patch", "pods", func(a k8stesting.Action) (bool, runtime.Object, error) {
+				if !c.wantPatch {
+					t.Fatal("Pod was patched unexpectedly")
+				}
+				patchCalled = true
+				return false, nil, nil
+			})
 			if err := UpdateReady(ctx, kubeclient, c.pod); (err != nil) != c.wantErr {
 				t.Errorf("UpdateReady (wantErr=%t): %v", c.wantErr, err)
 			}
 
+			if c.wantPatch && !patchCalled {
+				t.Fatal("Pod was not patched")
+			}
+
 			got, err := kubeclient.CoreV1().Pods(c.pod.Namespace).Get(ctx, c.pod.Name, metav1.GetOptions{})
 			if err != nil {
 				t.Errorf("Getting pod %q after update: %v", c.pod.Name, err)