Skip to content

Commit e53d8c1

Browse files
imjasonhtekton-robot
authored andcommitted
Use PATCH to update ready annotation
This should be faster and more reliable than the get-modify-write we use today.
1 parent 2aef32b commit e53d8c1

File tree

2 files changed

+47
-24
lines changed

2 files changed

+47
-24
lines changed

pkg/pod/entrypoint.go

+24-17
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@ package pod
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"errors"
2223
"fmt"
24+
"log"
2325
"path/filepath"
2426
"strings"
2527

2628
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
29+
"gomodules.xyz/jsonpatch/v2"
2730
corev1 "k8s.io/api/core/v1"
2831
k8serrors "k8s.io/apimachinery/pkg/api/errors"
2932
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33+
"k8s.io/apimachinery/pkg/types"
3034
"k8s.io/client-go/kubernetes"
3135
)
3236

@@ -166,26 +170,29 @@ func collectResultsName(results []v1beta1.TaskResult) string {
166170
return strings.Join(resultNames, ",")
167171
}
168172

169-
// UpdateReady updates the Pod's annotations to signal the first step to start
170-
// by projecting the ready annotation via the Downward API.
171-
func UpdateReady(ctx context.Context, kubeclient kubernetes.Interface, pod corev1.Pod) error {
172-
newPod, err := kubeclient.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
173+
var replaceReadyPatchBytes []byte
174+
175+
func init() {
176+
// https://stackoverflow.com/questions/55573724/create-a-patch-to-add-a-kubernetes-annotation
177+
readyAnnotationPath := "/metadata/annotations/" + strings.Replace(readyAnnotation, "/", "~1", 1)
178+
var err error
179+
replaceReadyPatchBytes, err = json.Marshal([]jsonpatch.JsonPatchOperation{{
180+
Operation: "replace",
181+
Path: readyAnnotationPath,
182+
Value: readyAnnotationValue,
183+
}})
173184
if err != nil {
174-
return fmt.Errorf("error getting Pod %q when updating ready annotation: %w", pod.Name, err)
185+
log.Fatalf("failed to marshal replace ready patch bytes: %v", err)
175186
}
187+
}
176188

177-
// Update the Pod's "READY" annotation to signal the first step to
178-
// start.
179-
if newPod.ObjectMeta.Annotations == nil {
180-
newPod.ObjectMeta.Annotations = map[string]string{}
181-
}
182-
if newPod.ObjectMeta.Annotations[readyAnnotation] != readyAnnotationValue {
183-
newPod.ObjectMeta.Annotations[readyAnnotation] = readyAnnotationValue
184-
if _, err := kubeclient.CoreV1().Pods(newPod.Namespace).Update(ctx, newPod, metav1.UpdateOptions{}); err != nil {
185-
return fmt.Errorf("error adding ready annotation to Pod %q: %w", pod.Name, err)
186-
}
187-
}
188-
return nil
189+
// UpdateReady updates the Pod's annotations to signal the first step to start
190+
// by projecting the ready annotation via the Downward API.
191+
func UpdateReady(ctx context.Context, kubeclient kubernetes.Interface, pod corev1.Pod) error {
192+
// PATCH the Pod's annotations to replace the ready annotation with the
193+
// "READY" value, to signal the first step to start.
194+
_, err := kubeclient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, types.JSONPatchType, replaceReadyPatchBytes, metav1.PatchOptions{})
195+
return err
189196
}
190197

191198
// StopSidecars updates sidecar containers in the Pod to a nop image, which

pkg/pod/entrypoint_test.go

+23-7
Original file line numberDiff line numberDiff line change
@@ -263,24 +263,38 @@ func TestUpdateReady(t *testing.T) {
263263
desc string
264264
pod corev1.Pod
265265
wantAnnotations map[string]string
266+
wantErr bool
266267
}{{
267-
desc: "Pod without any annotations has it added",
268+
desc: "Pod without any annotations fails",
268269
pod: corev1.Pod{
269270
ObjectMeta: metav1.ObjectMeta{
270271
Name: "pod",
271272
Annotations: nil,
272273
},
273274
},
275+
wantErr: true, // Nothing to replace.
276+
}, {
277+
desc: "Pod without ready annotation adds it",
278+
pod: corev1.Pod{
279+
ObjectMeta: metav1.ObjectMeta{
280+
Name: "pod",
281+
Annotations: map[string]string{
282+
"something": "else",
283+
},
284+
},
285+
},
274286
wantAnnotations: map[string]string{
275-
readyAnnotation: readyAnnotationValue,
287+
"something": "else",
288+
readyAnnotation: "READY",
276289
},
277290
}, {
278-
desc: "Pod with existing annotations has it appended",
291+
desc: "Pod with empty annotation value has it replaced",
279292
pod: corev1.Pod{
280293
ObjectMeta: metav1.ObjectMeta{
281294
Name: "pod",
282295
Annotations: map[string]string{
283-
"something": "else",
296+
"something": "else",
297+
readyAnnotation: "",
284298
},
285299
},
286300
},
@@ -289,16 +303,18 @@ func TestUpdateReady(t *testing.T) {
289303
readyAnnotation: readyAnnotationValue,
290304
},
291305
}, {
292-
desc: "Pod with other annotation value has it updated",
306+
desc: "Pod with other annotation value has it replaced",
293307
pod: corev1.Pod{
294308
ObjectMeta: metav1.ObjectMeta{
295309
Name: "pod",
296310
Annotations: map[string]string{
311+
"something": "else",
297312
readyAnnotation: "something else",
298313
},
299314
},
300315
},
301316
wantAnnotations: map[string]string{
317+
"something": "else",
302318
readyAnnotation: readyAnnotationValue,
303319
},
304320
}} {
@@ -307,8 +323,8 @@ func TestUpdateReady(t *testing.T) {
307323
ctx, cancel := context.WithCancel(ctx)
308324
defer cancel()
309325
kubeclient := fakek8s.NewSimpleClientset(&c.pod)
310-
if err := UpdateReady(ctx, kubeclient, c.pod); err != nil {
311-
t.Errorf("UpdateReady: %v", err)
326+
if err := UpdateReady(ctx, kubeclient, c.pod); (err != nil) != c.wantErr {
327+
t.Errorf("UpdateReady (wantErr=%t): %v", c.wantErr, err)
312328
}
313329

314330
got, err := kubeclient.CoreV1().Pods(c.pod.Namespace).Get(ctx, c.pod.Name, metav1.GetOptions{})

0 commit comments

Comments
 (0)