Skip to content

Commit 066bab4

Browse files
Make set CreationTimestamp optional
1 parent 8229d71 commit 066bab4

File tree

3 files changed

+65
-29
lines changed

3 files changed

+65
-29
lines changed

pkg/client/fake/client.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ type fakeClient struct {
9595
// indexesLock must be held when accessing indexes.
9696
indexesLock sync.RWMutex
9797

98-
returnManagedFields bool
98+
returnManagedFields bool
99+
setCreationTimestamp bool
99100
}
100101

101102
var _ client.WithWatch = &fakeClient{}
@@ -131,6 +132,7 @@ type ClientBuilder struct {
131132
interceptorFuncs *interceptor.Funcs
132133
typeConverters []managedfields.TypeConverter
133134
returnManagedFields bool
135+
setCreationTimestamp bool
134136
isBuilt bool
135137

136138
// indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK.
@@ -256,6 +258,13 @@ func (f *ClientBuilder) WithReturnManagedFields() *ClientBuilder {
256258
return f
257259
}
258260

261+
// WithSetCreationTimestamp configures the fake client to set metadata.creationTimestamp on Create and first Apply.
262+
// on objects.
263+
func (f *ClientBuilder) WithSetCreationTimestamp() *ClientBuilder {
264+
f.setCreationTimestamp = true
265+
return f
266+
}
267+
259268
// Build builds and returns a new fake client.
260269
func (f *ClientBuilder) Build() client.WithWatch {
261270
if f.isBuilt {
@@ -307,6 +316,7 @@ func (f *ClientBuilder) Build() client.WithWatch {
307316
scheme: f.scheme,
308317
withStatusSubresource: withStatusSubResource,
309318
usesFieldManagedObjectTracker: usesFieldManagedObjectTracker,
319+
setCreationTimestamp: f.setCreationTimestamp,
310320
}
311321

312322
for _, obj := range f.initObject {
@@ -332,6 +342,7 @@ func (f *ClientBuilder) Build() client.WithWatch {
332342
indexes: f.indexes,
333343
withStatusSubresource: withStatusSubResource,
334344
returnManagedFields: f.returnManagedFields,
345+
setCreationTimestamp: f.setCreationTimestamp,
335346
}
336347

337348
if f.interceptorFuncs != nil {
@@ -934,13 +945,15 @@ func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client
934945
// which allows to set it on create, but will then ignore it.
935946
obj.SetResourceVersion("1")
936947

937-
now, err := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
938-
if err != nil {
939-
return apierrors.NewInternalError(err)
948+
if c.setCreationTimestamp {
949+
now, err := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
950+
if err != nil {
951+
return apierrors.NewInternalError(err)
952+
}
953+
obj.SetCreationTimestamp(metav1.Time{
954+
Time: now,
955+
})
940956
}
941-
obj.SetCreationTimestamp(metav1.Time{
942-
Time: now,
943-
})
944957
} else {
945958
// SSA deletionTimestamp updates are silently ignored
946959
obj.SetDeletionTimestamp(oldAccessor.GetDeletionTimestamp())

pkg/client/fake/client_test.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -414,29 +414,41 @@ var _ = Describe("Fake client", func() {
414414
Expect(err).ToNot(HaveOccurred())
415415
Expect(obj).To(Equal(newcm))
416416
Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1"))
417-
Expect(obj.ObjectMeta.CreationTimestamp.IsZero()).To(BeFalse())
417+
Expect(obj.ObjectMeta.CreationTimestamp.IsZero()).To(BeTrue())
418418
})
419419

420-
It("should error on create with set resourceVersion", func(ctx SpecContext) {
420+
It("should be able to Create and set metadata.CreationTimestamp when required to do so", func(ctx SpecContext) {
421421
By("Creating a new configmap")
422+
cl := NewClientBuilder().WithSetCreationTimestamp().Build()
422423
newcm := &corev1.ConfigMap{
423424
ObjectMeta: metav1.ObjectMeta{
424-
Name: "new-test-cm",
425-
Namespace: "ns2",
426-
ResourceVersion: "1",
425+
Name: "test-cm-with-creation-timestamp",
426+
Namespace: "ns2",
427427
},
428428
}
429429
err := cl.Create(ctx, newcm)
430-
Expect(apierrors.IsBadRequest(err)).To(BeTrue())
430+
Expect(err).ToNot(HaveOccurred())
431+
432+
By("Getting the new configmap")
433+
namespacedName := types.NamespacedName{
434+
Name: "test-cm-with-creation-timestamp",
435+
Namespace: "ns2",
436+
}
437+
obj := &corev1.ConfigMap{}
438+
err = cl.Get(ctx, namespacedName, obj)
439+
Expect(err).ToNot(HaveOccurred())
440+
Expect(obj).To(Equal(newcm))
441+
Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1"))
442+
Expect(obj.ObjectMeta.CreationTimestamp.IsZero()).ToNot(BeTrue())
431443
})
432444

433-
It("should error on create with set creationTimestamp", func(ctx SpecContext) {
445+
It("should error on create with set resourceVersion", func(ctx SpecContext) {
434446
By("Creating a new configmap")
435447
newcm := &corev1.ConfigMap{
436448
ObjectMeta: metav1.ObjectMeta{
437-
Name: "new-test-cm",
438-
Namespace: "ns2",
439-
CreationTimestamp: metav1.Now(),
449+
Name: "new-test-cm",
450+
Namespace: "ns2",
451+
ResourceVersion: "1",
440452
},
441453
}
442454
err := cl.Create(ctx, newcm)
@@ -3082,13 +3094,23 @@ var _ = Describe("Fake client", func() {
30823094
Expect(obj.ResourceVersion).To(BeEquivalentTo(ptr.To("1")))
30833095
})
30843096

3085-
It("sets creatioTimestamp on SSA create", func(ctx SpecContext) {
3097+
It("does not set creatioTimestamp on SSA create", func(ctx SpecContext) {
30863098
obj := corev1applyconfigurations.
30873099
ConfigMap("foo", "default").
30883100
WithData(map[string]string{"some": "data"})
30893101

30903102
cl := NewClientBuilder().Build()
30913103
Expect(cl.Apply(ctx, obj, client.FieldOwner("foo"))).NotTo(HaveOccurred())
3104+
Expect(obj.CreationTimestamp.IsZero()).To(BeTrue())
3105+
})
3106+
3107+
It("sets creatioTimestamp on SSA create when required to do so", func(ctx SpecContext) {
3108+
obj := corev1applyconfigurations.
3109+
ConfigMap("foo", "default").
3110+
WithData(map[string]string{"some": "data"})
3111+
3112+
cl := NewClientBuilder().WithSetCreationTimestamp().Build()
3113+
Expect(cl.Apply(ctx, obj, client.FieldOwner("foo"))).NotTo(HaveOccurred())
30923114
Expect(obj.CreationTimestamp.IsZero()).To(BeFalse())
30933115
})
30943116

pkg/client/fake/versioned_tracker.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"bytes"
2121
"errors"
2222
"fmt"
23-
"reflect"
2423
"runtime/debug"
2524
"strconv"
2625
"time"
@@ -47,6 +46,7 @@ type versionedTracker struct {
4746
scheme *runtime.Scheme
4847
withStatusSubresource sets.Set[schema.GroupVersionKind]
4948
usesFieldManagedObjectTracker bool
49+
setCreationTimestamp bool
5050
}
5151

5252
func (t versionedTracker) Add(obj runtime.Object) error {
@@ -114,23 +114,24 @@ func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Ob
114114
return apierrors.NewBadRequest("resourceVersion can not be set for Create requests")
115115
}
116116
accessor.SetResourceVersion("1")
117-
if !reflect.DeepEqual(accessor.GetCreationTimestamp(), metav1.Time{}) {
118-
return apierrors.NewBadRequest("creationTimestamp can not be set for Create requests")
119-
}
120-
now, err := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
121-
if err != nil {
122-
return apierrors.NewInternalError(err)
117+
118+
originalCreationTimestamp := accessor.GetCreationTimestamp()
119+
if t.setCreationTimestamp {
120+
now, err := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
121+
if err != nil {
122+
return apierrors.NewInternalError(err)
123+
}
124+
accessor.SetCreationTimestamp(metav1.Time{
125+
Time: now,
126+
})
123127
}
124-
accessor.SetCreationTimestamp(metav1.Time{
125-
Time: now,
126-
})
127128
obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj)
128129
if err != nil {
129130
return err
130131
}
131132
if err := t.upstream.Create(gvr, obj, ns, opts...); err != nil {
132133
accessor.SetResourceVersion("")
133-
accessor.SetCreationTimestamp(metav1.Time{})
134+
accessor.SetCreationTimestamp(originalCreationTimestamp)
134135
return err
135136
}
136137

0 commit comments

Comments
 (0)