Skip to content

Commit d674baa

Browse files
Make set CreationTimestamp optional
1 parent 8229d71 commit d674baa

File tree

3 files changed

+77
-35
lines changed

3 files changed

+77
-35
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: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ 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

420420
It("should error on create with set resourceVersion", func(ctx SpecContext) {
@@ -430,19 +430,6 @@ var _ = Describe("Fake client", func() {
430430
Expect(apierrors.IsBadRequest(err)).To(BeTrue())
431431
})
432432

433-
It("should error on create with set creationTimestamp", func(ctx SpecContext) {
434-
By("Creating a new configmap")
435-
newcm := &corev1.ConfigMap{
436-
ObjectMeta: metav1.ObjectMeta{
437-
Name: "new-test-cm",
438-
Namespace: "ns2",
439-
CreationTimestamp: metav1.Now(),
440-
},
441-
}
442-
err := cl.Create(ctx, newcm)
443-
Expect(apierrors.IsBadRequest(err)).To(BeTrue())
444-
})
445-
446433
It("should not change the submitted object if Create failed", func(ctx SpecContext) {
447434
By("Trying to create an existing configmap")
448435
submitted := cm.DeepCopy()
@@ -1243,7 +1230,6 @@ var _ = Describe("Fake client", func() {
12431230
Expect(err).ToNot(HaveOccurred())
12441231
Expect(newObj.Finalizers).To(BeEmpty())
12451232
})
1246-
12471233
}
12481234

12491235
Context("with default scheme.Scheme", func() {
@@ -1487,6 +1473,48 @@ var _ = Describe("Fake client", func() {
14871473
})
14881474
})
14891475

1476+
Context("with SetCreationTimestamp option", func() {
1477+
BeforeEach(func() {
1478+
cl = NewClientBuilder().
1479+
WithSetCreationTimestamp().
1480+
Build()
1481+
})
1482+
1483+
It("should be able to Create and set metadata.CreationTimestamp", func(ctx SpecContext) {
1484+
By("Creating a new configmap")
1485+
newcm := &corev1.ConfigMap{
1486+
ObjectMeta: metav1.ObjectMeta{
1487+
Name: "test-cm-with-creation-timestamp",
1488+
Namespace: "ns2",
1489+
},
1490+
}
1491+
err := cl.Create(ctx, newcm)
1492+
Expect(err).ToNot(HaveOccurred())
1493+
1494+
By("Getting the new configmap")
1495+
namespacedName := types.NamespacedName{
1496+
Name: "test-cm-with-creation-timestamp",
1497+
Namespace: "ns2",
1498+
}
1499+
obj := &corev1.ConfigMap{}
1500+
err = cl.Get(ctx, namespacedName, obj)
1501+
Expect(err).ToNot(HaveOccurred())
1502+
Expect(obj).To(Equal(newcm))
1503+
Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1"))
1504+
Expect(obj.ObjectMeta.CreationTimestamp.IsZero()).ToNot(BeTrue())
1505+
})
1506+
1507+
It("sets creatioTimestamp on SSA create when required to do so", func(ctx SpecContext) {
1508+
obj := corev1applyconfigurations.
1509+
ConfigMap("foo-with-creation-timestamp", "default").
1510+
WithData(map[string]string{"some": "data"})
1511+
1512+
cl := NewClientBuilder().WithSetCreationTimestamp().Build()
1513+
Expect(cl.Apply(ctx, obj, client.FieldOwner("foo"))).NotTo(HaveOccurred())
1514+
Expect(obj.CreationTimestamp.IsZero()).To(BeFalse())
1515+
})
1516+
})
1517+
14901518
It("should set the ResourceVersion to 999 when adding an object to the tracker", func(ctx SpecContext) {
14911519
cl := NewClientBuilder().WithObjects(&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "cm"}}).Build()
14921520

@@ -3082,14 +3110,14 @@ var _ = Describe("Fake client", func() {
30823110
Expect(obj.ResourceVersion).To(BeEquivalentTo(ptr.To("1")))
30833111
})
30843112

3085-
It("sets creatioTimestamp on SSA create", func(ctx SpecContext) {
3113+
It("does not set creatioTimestamp on SSA create", func(ctx SpecContext) {
30863114
obj := corev1applyconfigurations.
30873115
ConfigMap("foo", "default").
30883116
WithData(map[string]string{"some": "data"})
30893117

30903118
cl := NewClientBuilder().Build()
30913119
Expect(cl.Apply(ctx, obj, client.FieldOwner("foo"))).NotTo(HaveOccurred())
3092-
Expect(obj.CreationTimestamp.IsZero()).To(BeFalse())
3120+
Expect(obj.CreationTimestamp.IsZero()).To(BeTrue())
30933121
})
30943122

30953123
It("ignores a passed resourceVersion on SSA create", func(ctx SpecContext) {

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)