Skip to content

Commit 83a129c

Browse files
committed
Add items to cache immediately after apply
This improves the SSA helper by avoding a second no-op patch just to add items to the cache. Instead we calculate the new request identifier and add to the cache directly. Signed-off-by: Lennart Jern <[email protected]>
1 parent 0978f70 commit 83a129c

File tree

2 files changed

+48
-17
lines changed

2 files changed

+48
-17
lines changed

internal/util/ssa/patch.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func Patch(ctx context.Context, c client.Client, fieldManager string, modified c
7575
if err != nil {
7676
return err
7777
}
78+
modifiedUnstructuredBeforeApply := modifiedUnstructured.DeepCopy()
7879

7980
gvk, err := apiutil.GVKForObject(modifiedUnstructured, c.Scheme())
8081
if err != nil {
@@ -119,10 +120,14 @@ func Patch(ctx context.Context, c client.Client, fieldManager string, modified c
119120
modified.GetObjectKind().SetGroupVersionKind(gvk)
120121

121122
if options.WithCachingProxy {
122-
// If the SSA call did not update the object, add the request to the cache.
123-
if options.Original.GetResourceVersion() == modifiedUnstructured.GetResourceVersion() {
124-
options.Cache.Add(requestIdentifier)
123+
// If the object changed, we need to recompute the request identifier before caching.
124+
if options.Original.GetResourceVersion() != modifiedUnstructured.GetResourceVersion() {
125+
requestIdentifier, err = ComputeRequestIdentifier(c.Scheme(), modifiedUnstructuredBeforeApply, modifiedUnstructured)
126+
if err != nil {
127+
return errors.Wrapf(err, "failed to compute request identifier after apply")
128+
}
125129
}
130+
options.Cache.Add(requestIdentifier)
126131
}
127132

128133
return nil

internal/util/ssa/patch_test.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,33 @@ func TestPatch(t *testing.T) {
5252
createObject := initialObject.DeepCopy()
5353
g.Expect(Patch(ctx, env.GetClient(), fieldManager, createObject)).To(Succeed())
5454

55-
// 2. Update the object and verify that the request was not cached as the object was changed.
55+
// 2. Update the object and verify that the request was not cached with the old identifier,
56+
// but is cached with a new identifier (after apply).
5657
// Get the original object.
5758
originalObject := initialObject.DeepCopy()
5859
g.Expect(env.GetAPIReader().Get(ctx, client.ObjectKeyFromObject(originalObject), originalObject)).To(Succeed())
5960
// Modify the object
6061
modifiedObject := initialObject.DeepCopy()
6162
g.Expect(unstructured.SetNestedField(modifiedObject.Object, "baz", "spec", "foo")).To(Succeed())
62-
// Compute request identifier, so we can later verify that the update call was not cached.
63+
// Compute request identifier before the update, so we can later verify that the update call was not cached with this identifier.
6364
modifiedUnstructured, err := prepareModified(env.Scheme(), modifiedObject)
6465
g.Expect(err).ToNot(HaveOccurred())
65-
requestIdentifier, err := ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
66+
oldRequestIdentifier, err := ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
6667
g.Expect(err).ToNot(HaveOccurred())
68+
// Save a copy of modifiedUnstructured before apply to compute the new identifier later
69+
modifiedUnstructuredBeforeApply := modifiedUnstructured.DeepCopy()
6770
// Update the object
6871
g.Expect(Patch(ctx, env.GetClient(), fieldManager, modifiedObject, WithCachingProxy{Cache: ssaCache, Original: originalObject})).To(Succeed())
69-
// Verify that request was not cached (as it changed the object)
70-
g.Expect(ssaCache.Has(requestIdentifier, initialObject.GetKind())).To(BeFalse())
72+
// Verify that request was not cached with the old identifier (as it changed the object)
73+
g.Expect(ssaCache.Has(oldRequestIdentifier, initialObject.GetKind())).To(BeFalse())
74+
// Get the actual object from server after apply to compute the new request identifier
75+
objectAfterApply := initialObject.DeepCopy()
76+
g.Expect(env.GetAPIReader().Get(ctx, client.ObjectKeyFromObject(objectAfterApply), objectAfterApply)).To(Succeed())
77+
// Compute the new request identifier (after apply)
78+
newRequestIdentifier, err := ComputeRequestIdentifier(env.GetScheme(), modifiedUnstructuredBeforeApply, objectAfterApply)
79+
g.Expect(err).ToNot(HaveOccurred())
80+
// Verify that request was cached with the new identifier (after apply)
81+
g.Expect(ssaCache.Has(newRequestIdentifier, initialObject.GetKind())).To(BeTrue())
7182

7283
// 3. Repeat the same update and verify that the request was cached as the object was not changed.
7384
// Get the original object.
@@ -79,12 +90,12 @@ func TestPatch(t *testing.T) {
7990
// Compute request identifier, so we can later verify that the update call was cached.
8091
modifiedUnstructured, err = prepareModified(env.Scheme(), modifiedObject)
8192
g.Expect(err).ToNot(HaveOccurred())
82-
requestIdentifier, err = ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
93+
requestIdentifierNoOp, err := ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
8394
g.Expect(err).ToNot(HaveOccurred())
8495
// Update the object
8596
g.Expect(Patch(ctx, env.GetClient(), fieldManager, modifiedObject, WithCachingProxy{Cache: ssaCache, Original: originalObject})).To(Succeed())
8697
// Verify that request was cached (as it did not change the object)
87-
g.Expect(ssaCache.Has(requestIdentifier, initialObject.GetKind())).To(BeTrue())
98+
g.Expect(ssaCache.Has(requestIdentifierNoOp, initialObject.GetKind())).To(BeTrue())
8899
})
89100

90101
t.Run("Test patch with Machine", func(*testing.T) {
@@ -129,24 +140,39 @@ func TestPatch(t *testing.T) {
129140
// Verify that gvk is still set
130141
g.Expect(createObject.GroupVersionKind()).To(Equal(initialObject.GroupVersionKind()))
131142

132-
// 2. Update the object and verify that the request was not cached as the object was changed.
143+
// 2. Update the object and verify that the request was not cached with the old identifier,
144+
// but is cached with a new identifier (after apply).
133145
// Get the original object.
134146
originalObject := initialObject.DeepCopy()
135147
g.Expect(env.GetAPIReader().Get(ctx, client.ObjectKeyFromObject(originalObject), originalObject)).To(Succeed())
136148
// Modify the object
137149
modifiedObject := initialObject.DeepCopy()
138150
modifiedObject.Spec.Deletion.NodeDrainTimeoutSeconds = ptr.To(int32(5))
139-
// Compute request identifier, so we can later verify that the update call was not cached.
151+
// Compute request identifier before the update, so we can later verify that the update call was not cached with this identifier.
140152
modifiedUnstructured, err := prepareModified(env.Scheme(), modifiedObject)
141153
g.Expect(err).ToNot(HaveOccurred())
142-
requestIdentifier, err := ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
154+
oldRequestIdentifier, err := ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
143155
g.Expect(err).ToNot(HaveOccurred())
156+
// Save a copy of modifiedUnstructured before apply to compute the new identifier later
157+
modifiedUnstructuredBeforeApply := modifiedUnstructured.DeepCopy()
144158
// Update the object
145159
g.Expect(Patch(ctx, env.GetClient(), fieldManager, modifiedObject, WithCachingProxy{Cache: ssaCache, Original: originalObject})).To(Succeed())
146160
// Verify that gvk is still set
147161
g.Expect(modifiedObject.GroupVersionKind()).To(Equal(initialObject.GroupVersionKind()))
148-
// Verify that request was not cached (as it changed the object)
149-
g.Expect(ssaCache.Has(requestIdentifier, initialObject.GetObjectKind().GroupVersionKind().Kind)).To(BeFalse())
162+
// Verify that request was not cached with the old identifier (as it changed the object)
163+
g.Expect(ssaCache.Has(oldRequestIdentifier, initialObject.GetObjectKind().GroupVersionKind().Kind)).To(BeFalse())
164+
// Get the actual object from server after apply to compute the new request identifier
165+
objectAfterApply := initialObject.DeepCopy()
166+
g.Expect(env.GetAPIReader().Get(ctx, client.ObjectKeyFromObject(objectAfterApply), objectAfterApply)).To(Succeed())
167+
// Convert to unstructured WITHOUT filtering to preserve server fields (like resourceVersion)
168+
objectAfterApplyUnstructured := &unstructured.Unstructured{}
169+
err = env.GetScheme().Convert(objectAfterApply, objectAfterApplyUnstructured, nil)
170+
g.Expect(err).ToNot(HaveOccurred())
171+
// Compute the new request identifier (after apply)
172+
newRequestIdentifier, err := ComputeRequestIdentifier(env.GetScheme(), modifiedUnstructuredBeforeApply, objectAfterApplyUnstructured)
173+
g.Expect(err).ToNot(HaveOccurred())
174+
// Verify that request was cached with the new identifier (after apply)
175+
g.Expect(ssaCache.Has(newRequestIdentifier, initialObject.GetObjectKind().GroupVersionKind().Kind)).To(BeTrue())
150176

151177
// Wait for 1 second. We are also trying to verify in this test that the resourceVersion of the Machine
152178
// is not increased. Under some circumstances this would only happen if the timestamp in managedFields would
@@ -166,12 +192,12 @@ func TestPatch(t *testing.T) {
166192
// Compute request identifier, so we can later verify that the update call was cached.
167193
modifiedUnstructured, err = prepareModified(env.Scheme(), modifiedObject)
168194
g.Expect(err).ToNot(HaveOccurred())
169-
requestIdentifier, err = ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
195+
requestIdentifierNoOp, err := ComputeRequestIdentifier(env.GetScheme(), originalObject, modifiedUnstructured)
170196
g.Expect(err).ToNot(HaveOccurred())
171197
// Update the object
172198
g.Expect(Patch(ctx, env.GetClient(), fieldManager, modifiedObject, WithCachingProxy{Cache: ssaCache, Original: originalObject})).To(Succeed())
173199
// Verify that request was cached (as it did not change the object)
174-
g.Expect(ssaCache.Has(requestIdentifier, initialObject.GetObjectKind().GroupVersionKind().Kind)).To(BeTrue())
200+
g.Expect(ssaCache.Has(requestIdentifierNoOp, initialObject.GetObjectKind().GroupVersionKind().Kind)).To(BeTrue())
175201
// Verify that gvk is still set
176202
g.Expect(modifiedObject.GroupVersionKind()).To(Equal(initialObject.GroupVersionKind()))
177203
})

0 commit comments

Comments
 (0)