Skip to content

Commit 3b9f0e2

Browse files
author
Grant Griffiths
committed
Fix unit tests and don't patch with empty finalizers
Signed-off-by: Grant Griffiths <[email protected]>
1 parent 2039ad9 commit 3b9f0e2

File tree

7 files changed

+161
-26
lines changed

7 files changed

+161
-26
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.16
44

55
require (
66
github.com/container-storage-interface/spec v1.5.0
7+
github.com/evanphx/json-patch v4.11.0+incompatible
78
github.com/fsnotify/fsnotify v1.4.9
89
github.com/golang/mock v1.4.4
910
github.com/golang/protobuf v1.5.2

pkg/common-controller/framework_test.go

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package common_controller
1818

1919
import (
20+
"encoding/json"
2021
"errors"
2122
"fmt"
2223
"net/http"
@@ -29,8 +30,7 @@ import (
2930
"testing"
3031
"time"
3132

32-
"k8s.io/client-go/util/workqueue"
33-
33+
jsonpatch "github.com/evanphx/json-patch"
3434
crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
3535
clientset "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned"
3636
"github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned/fake"
@@ -55,6 +55,7 @@ import (
5555
core "k8s.io/client-go/testing"
5656
"k8s.io/client-go/tools/cache"
5757
"k8s.io/client-go/tools/record"
58+
"k8s.io/client-go/util/workqueue"
5859
klog "k8s.io/klog/v2"
5960
)
6061

@@ -258,6 +259,46 @@ func (r *snapshotReactor) React(action core.Action) (handled bool, ret runtime.O
258259
klog.V(4).Infof("saved updated content %s", content.Name)
259260
return true, content, nil
260261

262+
case action.Matches("patch", "volumesnapshotcontents"):
263+
content := &crdv1.VolumeSnapshotContent{}
264+
action := action.(core.PatchAction)
265+
266+
// Check and bump object version
267+
storedSnapshotContent, found := r.contents[action.GetName()]
268+
if found {
269+
// Apply patch
270+
storedSnapshotBytes, err := json.Marshal(storedSnapshotContent)
271+
if err != nil {
272+
return true, nil, err
273+
}
274+
contentPatch, err := jsonpatch.DecodePatch(action.GetPatch())
275+
if err != nil {
276+
return true, nil, err
277+
}
278+
279+
modified, err := contentPatch.Apply(storedSnapshotBytes)
280+
if err != nil {
281+
return true, nil, err
282+
}
283+
284+
err = json.Unmarshal(modified, content)
285+
if err != nil {
286+
return true, nil, err
287+
}
288+
289+
storedVer, _ := strconv.Atoi(content.ResourceVersion)
290+
content.ResourceVersion = strconv.Itoa(storedVer + 1)
291+
} else {
292+
return true, nil, fmt.Errorf("cannot update snapshot content %s: snapshot content not found", action.GetName())
293+
}
294+
295+
// Store the updated object to appropriate places.
296+
r.contents[content.Name] = content
297+
r.changedObjects = append(r.changedObjects, content)
298+
r.changedSinceLastSync++
299+
klog.V(4).Infof("saved updated content %s", content.Name)
300+
return true, content, nil
301+
261302
case action.Matches("update", "volumesnapshots"):
262303
obj := action.(core.UpdateAction).GetObject()
263304
snapshot := obj.(*crdv1.VolumeSnapshot)
@@ -284,6 +325,52 @@ func (r *snapshotReactor) React(action core.Action) (handled bool, ret runtime.O
284325
klog.V(4).Infof("saved updated snapshot %s", snapshot.Name)
285326
return true, snapshot, nil
286327

328+
case action.Matches("patch", "volumesnapshots"):
329+
snapshot := &crdv1.VolumeSnapshot{}
330+
action := action.(core.PatchAction)
331+
332+
// Check and bump object version
333+
storedSnapshot, found := r.snapshots[action.GetName()]
334+
if found {
335+
// Apply patch
336+
storedSnapshotBytes, err := json.Marshal(storedSnapshot)
337+
if err != nil {
338+
return true, nil, err
339+
}
340+
snapPatch, err := jsonpatch.DecodePatch(action.GetPatch())
341+
if err != nil {
342+
return true, nil, err
343+
}
344+
345+
modified, err := snapPatch.Apply(storedSnapshotBytes)
346+
if err != nil {
347+
return true, nil, err
348+
}
349+
350+
err = json.Unmarshal(modified, storedSnapshot)
351+
if err != nil {
352+
return true, nil, err
353+
}
354+
355+
storedVer, _ := strconv.Atoi(storedSnapshot.ResourceVersion)
356+
storedSnapshot.ResourceVersion = strconv.Itoa(storedVer + 1)
357+
358+
// // If we were updating annotations and the new annotations are nil, leave as empty.
359+
// // This seems to be the behavior for merge-patching nil & empty annotations
360+
// if !reflect.DeepEqual(storedSnapshotContent.Annotations, content.Annotations) && content.Annotations == nil {
361+
// content.Annotations = make(map[string]string)
362+
// }
363+
} else {
364+
return true, nil, fmt.Errorf("cannot update snapshot %s: snapshot not found", action.GetName())
365+
}
366+
367+
// Store the updated object to appropriate places.
368+
r.snapshots[snapshot.Name] = storedSnapshot
369+
r.changedObjects = append(r.changedObjects, storedSnapshot)
370+
r.changedSinceLastSync++
371+
klog.V(4).Infof("saved updated snapshot %s", storedSnapshot.Name)
372+
return true, storedSnapshot, nil
373+
287374
case action.Matches("get", "volumesnapshotcontents"):
288375
name := action.(core.GetAction).GetName()
289376
content, found := r.contents[name]
@@ -437,6 +524,7 @@ func (r *snapshotReactor) checkContents(expectedContents []*crdv1.VolumeSnapshot
437524
}
438525
gotMap[v.Name] = v
439526
}
527+
440528
if !reflect.DeepEqual(expectedMap, gotMap) {
441529
// Print ugly but useful diff of expected and received objects for
442530
// easier debugging.
@@ -714,6 +802,8 @@ func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset,
714802
client.AddReactor("create", "volumesnapshotcontents", reactor.React)
715803
client.AddReactor("update", "volumesnapshotcontents", reactor.React)
716804
client.AddReactor("update", "volumesnapshots", reactor.React)
805+
client.AddReactor("patch", "volumesnapshotcontents", reactor.React)
806+
client.AddReactor("patch", "volumesnapshots", reactor.React)
717807
client.AddReactor("update", "volumesnapshotclasses", reactor.React)
718808
client.AddReactor("get", "volumesnapshotcontents", reactor.React)
719809
client.AddReactor("get", "volumesnapshots", reactor.React)

pkg/common-controller/snapshot_controller.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -809,13 +809,24 @@ func (ctrl *csiSnapshotCommonController) updateSnapshotErrorStatusWithEvent(snap
809809

810810
// addContentFinalizer adds a Finalizer for VolumeSnapshotContent.
811811
func (ctrl *csiSnapshotCommonController) addContentFinalizer(content *crdv1.VolumeSnapshotContent) error {
812+
812813
var patches []utils.PatchOp
813-
patches = append(patches, utils.PatchOp{
814-
Op: "add",
815-
Path: "/metadata/finalizers/-",
816-
Value: utils.VolumeSnapshotContentFinalizer,
817-
})
814+
if len(content.Finalizers) > 0 {
815+
// Add to the end of the finalizers if we have any other finalizers
816+
patches = append(patches, utils.PatchOp{
817+
Op: "add",
818+
Path: "/metadata/finalizers/-",
819+
Value: utils.VolumeSnapshotContentFinalizer,
820+
})
818821

822+
} else {
823+
// Replace finalizers with new array if there are no other finalizers
824+
patches = append(patches, utils.PatchOp{
825+
Op: "add",
826+
Path: "/metadata/finalizers",
827+
Value: []string{utils.VolumeSnapshotContentFinalizer},
828+
})
829+
}
819830
newContent, err := utils.PatchVolumeSnapshotContent(content, patches, ctrl.clientset)
820831
if err != nil {
821832
return newControllerUpdateError(content.Name, err.Error())
@@ -987,17 +998,6 @@ func (ctrl *csiSnapshotCommonController) checkandBindSnapshotContent(snapshot *c
987998
} else if content.Spec.VolumeSnapshotRef.UID != "" && content.Spec.VolumeSnapshotClassName != nil {
988999
return content, nil
9891000
}
990-
// contentClone := content.DeepCopy()
991-
// contentClone.Spec.VolumeSnapshotRef.UID = snapshot.UID
992-
// if snapshot.Spec.VolumeSnapshotClassName != nil {
993-
// className := *(snapshot.Spec.VolumeSnapshotClassName)
994-
// contentClone.Spec.VolumeSnapshotClassName = &className
995-
// }
996-
// newContent, err := ctrl.clientset.SnapshotV1().VolumeSnapshotContents().Update(context.TODO(), contentClone, metav1.UpdateOptions{})
997-
// if err != nil {
998-
// klog.V(4).Infof("updating VolumeSnapshotContent[%s] error status failed %v", contentClone.Name, err)
999-
// return content, err
1000-
// }
10011001

10021002
patches := []utils.PatchOp{
10031003
{

pkg/common-controller/snapshot_update_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func TestSync(t *testing.T) {
162162
expectedSnapshots: newSnapshotArray("snap2-12", "snapuid2-12", "", "content2-12", validSecretClass, "content2-12", &False, nil, nil, newVolumeError("Snapshot failed to bind VolumeSnapshotContent, mock update error"), false, true, nil),
163163
errors: []reactorError{
164164
// Inject error to the forth client.VolumesnapshotV1().VolumeSnapshots().Update call.
165-
{"update", "volumesnapshotcontents", errors.New("mock update error")},
165+
{"patch", "volumesnapshotcontents", errors.New("mock update error")},
166166
},
167167
test: testSyncSnapshot,
168168
},
@@ -312,7 +312,7 @@ func TestSync(t *testing.T) {
312312
initialSecrets: []*v1.Secret{secret()},
313313
errors: []reactorError{
314314
// Inject error to the forth client.VolumesnapshotV1().VolumeSnapshots().Update call.
315-
{"update", "volumesnapshotcontents", errors.New("mock update error")},
315+
{"patch", "volumesnapshotcontents", errors.New("mock update error")},
316316
},
317317
expectSuccess: false,
318318
test: testSyncContentError,

pkg/sidecar-controller/content_create_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func TestSyncContent(t *testing.T) {
8585
{
8686
name: "1-3: Basic sync content create snapshot with non-existent secret",
8787
initialContents: withContentAnnotations(withContentStatus(newContentArray("content1-3", "snapuid1-3", "snap1-3", "sid1-3", invalidSecretClass, "", "volume-handle-1-3", retainPolicy, nil, &defaultSize, true),
88-
nil), map[string]string{
88+
&crdv1.VolumeSnapshotContentStatus{}), map[string]string{
8989
utils.AnnDeletionSecretRefName: "",
9090
utils.AnnDeletionSecretRefNamespace: "",
9191
}),
@@ -94,12 +94,12 @@ func TestSyncContent(t *testing.T) {
9494
SnapshotHandle: nil,
9595
RestoreSize: nil,
9696
ReadyToUse: &False,
97-
Error: newSnapshotError("Failed to create snapshot: failed to get input parameters to create snapshot for content content1-3: \"cannot retrieve secrets for snapshot content \\\"content1-3\\\", err: secret name or namespace not specified\""),
97+
Error: newSnapshotError("Failed to check and update snapshot content: failed to get input parameters to create snapshot for content content1-3: \"cannot retrieve secrets for snapshot content \\\"content1-3\\\", err: secret name or namespace not specified\""),
9898
}), map[string]string{
9999
utils.AnnDeletionSecretRefName: "",
100100
utils.AnnDeletionSecretRefNamespace: "",
101101
}), initialSecrets: []*v1.Secret{}, // no initial secret created
102-
expectedEvents: []string{"Warning SnapshotCreationFailed"},
102+
expectedEvents: []string{"Warning SnapshotContentCheckandUpdateFailed"},
103103
errors: noerrors,
104104
test: testSyncContent,
105105
},
@@ -149,7 +149,7 @@ func TestSyncContent(t *testing.T) {
149149
{
150150
name: "1-5: Basic sync content create snapshot with failed secret call",
151151
initialContents: withContentAnnotations(withContentStatus(newContentArray("content1-5", "snapuid1-5", "snap1-5", "sid1-5", invalidSecretClass, "", "volume-handle-1-5", retainPolicy, nil, &defaultSize, true),
152-
nil), map[string]string{
152+
&crdv1.VolumeSnapshotContentStatus{}), map[string]string{
153153
utils.AnnDeletionSecretRefName: "secret",
154154
utils.AnnDeletionSecretRefNamespace: "default",
155155
}),
@@ -158,12 +158,12 @@ func TestSyncContent(t *testing.T) {
158158
SnapshotHandle: nil,
159159
RestoreSize: nil,
160160
ReadyToUse: &False,
161-
Error: newSnapshotError("Failed to create snapshot: failed to get input parameters to create snapshot for content content1-5: \"cannot get credentials for snapshot content \\\"content1-5\\\"\""),
161+
Error: newSnapshotError(`Failed to check and update snapshot content: failed to get input parameters to create snapshot for content content1-5: "cannot get credentials for snapshot content \"content1-5\""`),
162162
}), map[string]string{
163163
utils.AnnDeletionSecretRefName: "secret",
164164
utils.AnnDeletionSecretRefNamespace: "default",
165165
}), initialSecrets: []*v1.Secret{}, // no initial secret created
166-
expectedEvents: []string{"Warning SnapshotCreationFailed"},
166+
expectedEvents: []string{"Warning SnapshotContentCheckandUpdateFailed"},
167167
errors: []reactorError{
168168
// Inject error to the first client.VolumesnapshotV1().VolumeSnapshots().Update call.
169169
// All other calls will succeed.

pkg/sidecar-controller/framework_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package sidecar_controller
1515

1616
import (
1717
"context"
18+
"encoding/json"
1819
"errors"
1920
"fmt"
2021
"reflect"
@@ -25,6 +26,7 @@ import (
2526
"testing"
2627
"time"
2728

29+
jsonpatch "github.com/evanphx/json-patch"
2830
crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
2931
clientset "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned"
3032
"github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned/fake"
@@ -215,6 +217,46 @@ func (r *snapshotReactor) React(action core.Action) (handled bool, ret runtime.O
215217
klog.V(4).Infof("saved updated content %s", content.Name)
216218
return true, content, nil
217219

220+
case action.Matches("patch", "volumesnapshotcontents"):
221+
content := &crdv1.VolumeSnapshotContent{}
222+
action := action.(core.PatchAction)
223+
224+
// Check and bump object version
225+
storedSnapshotContent, found := r.contents[action.GetName()]
226+
if found {
227+
// Apply patch
228+
storedSnapshotBytes, err := json.Marshal(storedSnapshotContent)
229+
if err != nil {
230+
return true, nil, err
231+
}
232+
contentPatch, err := jsonpatch.DecodePatch(action.GetPatch())
233+
if err != nil {
234+
return true, nil, err
235+
}
236+
237+
modified, err := contentPatch.Apply(storedSnapshotBytes)
238+
if err != nil {
239+
return true, nil, err
240+
}
241+
242+
err = json.Unmarshal(modified, content)
243+
if err != nil {
244+
return true, nil, err
245+
}
246+
247+
storedVer, _ := strconv.Atoi(content.ResourceVersion)
248+
content.ResourceVersion = strconv.Itoa(storedVer + 1)
249+
} else {
250+
return true, nil, fmt.Errorf("cannot update snapshot content %s: snapshot content not found", action.GetName())
251+
}
252+
253+
// Store the updated object to appropriate places.
254+
r.contents[content.Name] = content
255+
r.changedObjects = append(r.changedObjects, content)
256+
r.changedSinceLastSync++
257+
klog.V(4).Infof("saved updated content %s", content.Name)
258+
return true, content, nil
259+
218260
case action.Matches("get", "volumesnapshotcontents"):
219261
name := action.(core.GetAction).GetName()
220262
content, found := r.contents[name]
@@ -488,6 +530,7 @@ func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset,
488530

489531
client.AddReactor("create", "volumesnapshotcontents", reactor.React)
490532
client.AddReactor("update", "volumesnapshotcontents", reactor.React)
533+
client.AddReactor("patch", "volumesnapshotcontents", reactor.React)
491534
client.AddReactor("get", "volumesnapshotcontents", reactor.React)
492535
client.AddReactor("delete", "volumesnapshotcontents", reactor.React)
493536
kubeClient.AddReactor("get", "secrets", reactor.React)

vendor/modules.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ github.com/container-storage-interface/spec/lib/go/csi
1010
# github.com/davecgh/go-spew v1.1.1
1111
github.com/davecgh/go-spew/spew
1212
# github.com/evanphx/json-patch v4.11.0+incompatible
13+
## explicit
1314
github.com/evanphx/json-patch
1415
# github.com/fsnotify/fsnotify v1.4.9
1516
## explicit

0 commit comments

Comments
 (0)