diff --git a/cmd/snapshot-controller/main.go b/cmd/snapshot-controller/main.go index ce7fc38fd..db8aea8a6 100644 --- a/cmd/snapshot-controller/main.go +++ b/cmd/snapshot-controller/main.go @@ -378,6 +378,6 @@ func buildConfig(kubeconfig string) (*rest.Config, error) { type promklog struct{} -func (pl promklog) Println(v ...interface{}) { +func (pl promklog) Println(v ...any) { klog.Error(v...) } diff --git a/pkg/common-controller/framework_test.go b/pkg/common-controller/framework_test.go index ecde1c100..5946d4a84 100644 --- a/pkg/common-controller/framework_test.go +++ b/pkg/common-controller/framework_test.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "net/http" "reflect" sysruntime "runtime" @@ -169,7 +170,7 @@ type snapshotReactor struct { groupContents map[string]*crdv1beta2.VolumeGroupSnapshotContent groupSnapshots map[string]*crdv1beta2.VolumeGroupSnapshot groupSnapshotClasses map[string]*crdv1beta2.VolumeGroupSnapshotClass - changedObjects []interface{} + changedObjects []any changedSinceLastSync int ctrl *csiSnapshotCommonController fakeContentWatch *watch.FakeWatcher @@ -208,9 +209,7 @@ func withClaimLabels(pvcs []*v1.PersistentVolumeClaim, labels map[string]string) if pvcs[i].ObjectMeta.Labels == nil { pvcs[i].ObjectMeta.Labels = make(map[string]string) } - for k, v := range labels { - pvcs[i].ObjectMeta.Labels[k] = v - } + maps.Copy(pvcs[i].ObjectMeta.Labels, labels) } return pvcs } @@ -237,18 +236,14 @@ func withVolumesLocalPath(pvs []*v1.PersistentVolume, path string) []*v1.Persist func withSnapshotFinalizers(snapshots []*crdv1.VolumeSnapshot, finalizers ...string) []*crdv1.VolumeSnapshot { for i := range snapshots { - for _, f := range finalizers { - snapshots[i].ObjectMeta.Finalizers = append(snapshots[i].ObjectMeta.Finalizers, f) - } + snapshots[i].ObjectMeta.Finalizers = append(snapshots[i].ObjectMeta.Finalizers, finalizers...) } return snapshots } func withGroupSnapshotFinalizers(groupSnapshots []*crdv1beta2.VolumeGroupSnapshot, finalizers ...string) []*crdv1beta2.VolumeGroupSnapshot { for i := range groupSnapshots { - for _, f := range finalizers { - groupSnapshots[i].ObjectMeta.Finalizers = append(groupSnapshots[i].ObjectMeta.Finalizers, f) - } + groupSnapshots[i].ObjectMeta.Finalizers = append(groupSnapshots[i].ObjectMeta.Finalizers, finalizers...) } return groupSnapshots } @@ -926,7 +921,7 @@ func checkEvents(t *testing.T, expectedEvents []string, ctrl *csiSnapshotCommonC klog.V(5).Infof("event recorder finished") finished = true } - case _, _ = <-timer.C: + case <-timer.C: klog.V(5).Infof("event recorder timeout") finished = true } @@ -952,77 +947,6 @@ func checkEvents(t *testing.T, expectedEvents []string, ctrl *csiSnapshotCommonC return err } -// popChange returns one recorded updated object, either *crdv1.VolumeSnapshotContent -// or *crdv1.VolumeSnapshot. Returns nil when there are no changes. -func (r *snapshotReactor) popChange() interface{} { - r.lock.Lock() - defer r.lock.Unlock() - - if len(r.changedObjects) == 0 { - return nil - } - - // For debugging purposes, print the queue - for _, obj := range r.changedObjects { - switch obj.(type) { - case *crdv1.VolumeSnapshotContent: - vol, _ := obj.(*crdv1.VolumeSnapshotContent) - klog.V(4).Infof("reactor queue: %s", vol.Name) - case *crdv1.VolumeSnapshot: - snapshot, _ := obj.(*crdv1.VolumeSnapshot) - klog.V(4).Infof("reactor queue: %s", snapshot.Name) - } - } - - // Pop the first item from the queue and return it - obj := r.changedObjects[0] - r.changedObjects = r.changedObjects[1:] - return obj -} - -// syncAll simulates the controller periodic sync of contents and snapshot. It -// simply adds all these objects to the internal queue of updates. This method -// should be used when the test manually calls syncSnapshot/syncContent. Test that -// use real controller loop (ctrl.Run()) will get periodic sync automatically. -func (r *snapshotReactor) syncAll() { - r.lock.Lock() - defer r.lock.Unlock() - - for _, c := range r.snapshots { - r.changedObjects = append(r.changedObjects, c) - } - for _, v := range r.contents { - r.changedObjects = append(r.changedObjects, v) - } - for _, pvc := range r.claims { - r.changedObjects = append(r.changedObjects, pvc) - } - r.changedSinceLastSync = 0 -} - -func (r *snapshotReactor) getChangeCount() int { - r.lock.Lock() - defer r.lock.Unlock() - return r.changedSinceLastSync -} - -// waitForIdle waits until all tests, controllers and other goroutines do their -// job and no new actions are registered for 10 milliseconds. -func (r *snapshotReactor) waitForIdle() { - // Check every 10ms if the controller does something and stop if it's - // idle. - oldChanges := -1 - for { - time.Sleep(10 * time.Millisecond) - changes := r.getChangeCount() - if changes == oldChanges { - // No changes for last 10ms -> controller must be idle. - break - } - oldChanges = changes - } -} - // waitTest waits until all tests, controllers and other goroutines do their // job and list of current contents/snapshots is equal to list of expected // contents/snapshots (with ~10 second timeout). @@ -1048,80 +972,6 @@ func (r *snapshotReactor) waitTest(test controllerTest) error { return err } -// deleteContentEvent simulates that a content has been deleted in etcd and -// the controller receives 'content deleted' event. -func (r *snapshotReactor) deleteContentEvent(content *crdv1.VolumeSnapshotContent) { - r.lock.Lock() - defer r.lock.Unlock() - - // Remove the content from list of resulting contents. - delete(r.contents, content.Name) - - // Generate deletion event. Cloned content is needed to prevent races (and we - // would get a clone from etcd too). - if r.fakeContentWatch != nil { - r.fakeContentWatch.Delete(content.DeepCopy()) - } -} - -// deleteSnapshotEvent simulates that a snapshot has been deleted in etcd and the -// controller receives 'snapshot deleted' event. -func (r *snapshotReactor) deleteSnapshotEvent(snapshot *crdv1.VolumeSnapshot) { - r.lock.Lock() - defer r.lock.Unlock() - - // Remove the snapshot from list of resulting snapshots. - delete(r.snapshots, snapshot.Name) - - // Generate deletion event. Cloned content is needed to prevent races (and we - // would get a clone from etcd too). - if r.fakeSnapshotWatch != nil { - r.fakeSnapshotWatch.Delete(snapshot.DeepCopy()) - } -} - -// addContentEvent simulates that a content has been added in etcd and the -// controller receives 'content added' event. -func (r *snapshotReactor) addContentEvent(content *crdv1.VolumeSnapshotContent) { - r.lock.Lock() - defer r.lock.Unlock() - - r.contents[content.Name] = content - // Generate event. No cloning is needed, this snapshot is not stored in the - // controller cache yet. - if r.fakeContentWatch != nil { - r.fakeContentWatch.Add(content) - } -} - -// modifyContentEvent simulates that a content has been modified in etcd and the -// controller receives 'content modified' event. -func (r *snapshotReactor) modifyContentEvent(content *crdv1.VolumeSnapshotContent) { - r.lock.Lock() - defer r.lock.Unlock() - - r.contents[content.Name] = content - // Generate deletion event. Cloned content is needed to prevent races (and we - // would get a clone from etcd too). - if r.fakeContentWatch != nil { - r.fakeContentWatch.Modify(content.DeepCopy()) - } -} - -// addSnapshotEvent simulates that a snapshot has been created in etcd and the -// controller receives 'snapshot added' event. -func (r *snapshotReactor) addSnapshotEvent(snapshot *crdv1.VolumeSnapshot) { - r.lock.Lock() - defer r.lock.Unlock() - - r.snapshots[snapshot.Name] = snapshot - // Generate event. No cloning is needed, this snapshot is not stored in the - // controller cache yet. - if r.fakeSnapshotWatch != nil { - r.fakeSnapshotWatch.Add(snapshot) - } -} - func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset, ctrl *csiSnapshotCommonController, fakeVolumeWatch, fakeClaimWatch *watch.FakeWatcher, errors []reactorError) *snapshotReactor { reactor := &snapshotReactor{ secrets: make(map[string]*v1.Secret), @@ -1174,8 +1024,7 @@ func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset, func alwaysReady() bool { return true } -func newTestController(kubeClient kubernetes.Interface, clientset clientset.Interface, - informerFactory informers.SharedInformerFactory, t *testing.T, test controllerTest) (*csiSnapshotCommonController, error) { +func newTestController(kubeClient kubernetes.Interface, clientset clientset.Interface, informerFactory informers.SharedInformerFactory, t *testing.T) (*csiSnapshotCommonController, error) { if informerFactory == nil { informerFactory = informers.NewSharedInformerFactory(clientset, utils.NoResyncPeriodFunc()) } @@ -1351,9 +1200,7 @@ func withContentAnnotations(contents []*crdv1.VolumeSnapshotContent, annotations if contents[i].ObjectMeta.Annotations == nil { contents[i].ObjectMeta.Annotations = make(map[string]string) } - for k, v := range annotations { - contents[i].ObjectMeta.Annotations[k] = v - } + maps.Copy(contents[i].ObjectMeta.Annotations, annotations) } return contents } @@ -1380,9 +1227,7 @@ func withGroupContentAnnotations(contents []*crdv1beta2.VolumeGroupSnapshotConte if contents[i].ObjectMeta.Annotations == nil { contents[i].ObjectMeta.Annotations = make(map[string]string) } - for k, v := range annotations { - contents[i].ObjectMeta.Annotations[k] = v - } + maps.Copy(contents[i].ObjectMeta.Annotations, annotations) } return contents } @@ -1413,16 +1258,6 @@ func newContentArrayWithReadyToUse(contentName, boundToSnapshotUID, boundToSnaps } } -func newContentWithUnmatchDriverArray(contentName, boundToSnapshotUID, boundToSnapshotName, snapshotHandle, snapshotClassName, desiredSnapshotHandle, volumeHandle string, - deletionPolicy crdv1.DeletionPolicy, size, creationTime *int64, - withFinalizer bool) []*crdv1.VolumeSnapshotContent { - content := newContent(contentName, boundToSnapshotUID, boundToSnapshotName, snapshotHandle, snapshotClassName, desiredSnapshotHandle, volumeHandle, deletionPolicy, size, creationTime, withFinalizer, true) - content.Spec.Driver = "fake" - return []*crdv1.VolumeSnapshotContent{ - content, - } -} - func newContentArrayWithError(contentName, boundToSnapshotUID, boundToSnapshotName, snapshotHandle, snapshotClassName, desiredSnapshotHandle, volumeHandle string, deletionPolicy crdv1.DeletionPolicy, size, creationTime *int64, withFinalizer bool, snapshotErr *crdv1.VolumeSnapshotError) []*crdv1.VolumeSnapshotContent { @@ -1549,30 +1384,6 @@ func newSnapshotArray( } } -func newSnapshotClass(snapshotClassName, snapshotClassUID, driverName string, isDefaultClass bool) *crdv1.VolumeSnapshotClass { - sc := &crdv1.VolumeSnapshotClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: snapshotClassName, - Namespace: testNamespace, - UID: types.UID(snapshotClassUID), - ResourceVersion: "1", - SelfLink: "/apis/snapshot.storage.k8s.io/v1/namespaces/" + testNamespace + "/volumesnapshotclasses/" + snapshotClassName, - }, - Driver: driverName, - } - if isDefaultClass { - sc.Annotations = make(map[string]string) - sc.Annotations[utils.IsDefaultSnapshotClassAnnotation] = "true" - } - return sc -} - -func newSnapshotClassArray(snapshotClassName, snapshotClassUID, driverName string, isDefaultClass bool) []*crdv1.VolumeSnapshotClass { - return []*crdv1.VolumeSnapshotClass{ - newSnapshotClass(snapshotClassName, snapshotClassUID, driverName, isDefaultClass), - } -} - // newClaim returns a new claim with given attributes func newClaim(name, claimUID, capacity, boundToVolume string, phase v1.PersistentVolumeClaimPhase, class *string, bFinalizer bool) *v1.PersistentVolumeClaim { claim := v1.PersistentVolumeClaim{ @@ -1650,7 +1461,7 @@ func newClaimArrayFinalizer(name, claimUID, capacity, boundToVolume string, phas } // newVolume returns a new volume with given attributes -func newVolume(name, volumeUID, volumeHandle, capacity, boundToClaimUID, boundToClaimName string, phase v1.PersistentVolumePhase, reclaimPolicy v1.PersistentVolumeReclaimPolicy, class string, annotations ...string) *v1.PersistentVolume { +func newVolume(name, volumeUID, volumeHandle, capacity, boundToClaimUID, boundToClaimName string, phase v1.PersistentVolumePhase, reclaimPolicy v1.PersistentVolumeReclaimPolicy, class string) *v1.PersistentVolume { volume := v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -1826,10 +1637,6 @@ var ( invalidSecretClass = "invalid-secret-class" validSecretClass = "valid-secret-class" sameDriver = "sameDriver" - diffDriver = "diffDriver" - noClaim = "" - noBoundUID = "" - noVolume = "" ) // wrapTestWithInjectedOperation returns a testCall that: @@ -1899,7 +1706,7 @@ func runSyncTests(t *testing.T, tests []controllerTest, snapshotClasses []*crdv1 kubeClient := &kubefake.Clientset{} client := &fake.Clientset{} - ctrl, err := newTestController(kubeClient, client, nil, t, test) + ctrl, err := newTestController(kubeClient, client, nil, t) if err != nil { t.Fatalf("Test %q construct persistent content failed: %v", test.name, err) } @@ -1976,7 +1783,7 @@ func runFinalizerTests(t *testing.T, tests []controllerTest, snapshotClasses []* kubeClient := &kubefake.Clientset{} client := &fake.Clientset{} - ctrl, err := newTestController(kubeClient, client, nil, t, test) + ctrl, err := newTestController(kubeClient, client, nil, t) if err != nil { t.Fatalf("Test %q construct persistent content failed: %v", test.name, err) } @@ -2019,12 +1826,12 @@ func runFinalizerTests(t *testing.T, tests []controllerTest, snapshotClasses []* } // Verify Finalizer tests results - evaluateFinalizerTests(ctrl, reactor, test, t) + evaluateFinalizerTests(reactor, test, t) } } // Evaluate Finalizer tests results -func evaluateFinalizerTests(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest, t *testing.T) { +func evaluateFinalizerTests(reactor *snapshotReactor, test controllerTest, t *testing.T) { // Evaluate results bHasPVCFinalizer := false bHasSnapshotFinalizer := false @@ -2118,7 +1925,7 @@ func runUpdateSnapshotClassTests(t *testing.T, tests []controllerTest, snapshotC kubeClient := &kubefake.Clientset{} client := &fake.Clientset{} - ctrl, err := newTestController(kubeClient, client, nil, t, test) + ctrl, err := newTestController(kubeClient, client, nil, t) if err != nil { t.Fatalf("Test %q construct test controller failed: %v", test.name, err) } @@ -2174,15 +1981,6 @@ func getSize(size int64) *resource.Quantity { return resource.NewQuantity(size, resource.BinarySI) } -func emptySecret() *v1.Secret { - return &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "emptysecret", - Namespace: "default", - }, - } -} - func secret() *v1.Secret { return &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -2194,25 +1992,3 @@ func secret() *v1.Secret { }, } } - -func secretAnnotations() map[string]string { - return map[string]string{ - utils.AnnDeletionSecretRefName: "secret", - utils.AnnDeletionSecretRefNamespace: "default", - } -} - -func emptyNamespaceSecretAnnotations() map[string]string { - return map[string]string{ - utils.AnnDeletionSecretRefName: "name", - utils.AnnDeletionSecretRefNamespace: "", - } -} - -// this refers to emptySecret(), which is missing data. -func emptyDataSecretAnnotations() map[string]string { - return map[string]string{ - utils.AnnDeletionSecretRefName: "emptysecret", - utils.AnnDeletionSecretRefNamespace: "default", - } -} diff --git a/pkg/common-controller/groupsnapshot_controller_helper.go b/pkg/common-controller/groupsnapshot_controller_helper.go index dee928b84..28f091693 100644 --- a/pkg/common-controller/groupsnapshot_controller_helper.go +++ b/pkg/common-controller/groupsnapshot_controller_helper.go @@ -38,11 +38,11 @@ import ( "github.com/kubernetes-csi/external-snapshotter/v8/pkg/utils" ) -func (ctrl *csiSnapshotCommonController) storeGroupSnapshotUpdate(groupsnapshot interface{}) (bool, error) { +func (ctrl *csiSnapshotCommonController) storeGroupSnapshotUpdate(groupsnapshot any) (bool, error) { return utils.StoreObjectUpdate(ctrl.groupSnapshotStore, groupsnapshot, "groupsnapshot") } -func (ctrl *csiSnapshotCommonController) storeGroupSnapshotContentUpdate(groupsnapshotcontent interface{}) (bool, error) { +func (ctrl *csiSnapshotCommonController) storeGroupSnapshotContentUpdate(groupsnapshotcontent any) (bool, error) { return utils.StoreObjectUpdate(ctrl.groupSnapshotContentStore, groupsnapshotcontent, "groupsnapshotcontent") } @@ -207,7 +207,7 @@ func (ctrl *csiSnapshotCommonController) getVolumesFromVolumeGroupSnapshot(group // Verify binding between PV/PVC is still valid bound := ctrl.isVolumeBoundToClaim(pv, &pvc) - if bound == false { + if !bound { klog.Warningf("binding between PV %s and PVC %s is broken", pvName, pvc.Name) return nil, fmt.Errorf("claim in dataSource not bound or invalid") } @@ -308,7 +308,7 @@ func (ctrl *csiSnapshotCommonController) syncGroupSnapshot(ctx context.Context, klog.V(5).Infof("syncGroupSnapshot[%s]: validate group snapshot to make sure source has been correctly specified", utils.GroupSnapshotKey(groupSnapshot)) if (groupSnapshot.Spec.Source.Selector == nil && groupSnapshot.Spec.Source.VolumeGroupSnapshotContentName == nil) || (groupSnapshot.Spec.Source.Selector != nil && groupSnapshot.Spec.Source.VolumeGroupSnapshotContentName != nil) { - err := fmt.Errorf("Exactly one of Selector and VolumeGroupSnapshotContentName should be specified") + err := fmt.Errorf("exactly one of Selector and VolumeGroupSnapshotContentName should be specified") klog.Errorf("syncGroupSnapshot[%s]: validation error, %s", utils.GroupSnapshotKey(groupSnapshot), err.Error()) ctrl.updateGroupSnapshotErrorStatusWithEvent(groupSnapshot, true, v1.EventTypeWarning, "GroupSnapshotValidationError", err.Error()) return err @@ -804,9 +804,9 @@ func (ctrl *csiSnapshotCommonController) getPreprovisionedGroupSnapshotContentFr // groupSnapshotContent.Spec.VolumeGroupSnapshotRef. func (ctrl *csiSnapshotCommonController) checkAndBindGroupSnapshotContent(groupSnapshot *crdv1beta2.VolumeGroupSnapshot, groupSnapshotContent *crdv1beta2.VolumeGroupSnapshotContent) (*crdv1beta2.VolumeGroupSnapshotContent, error) { if groupSnapshotContent.Spec.VolumeGroupSnapshotRef.Name != groupSnapshot.Name { - return nil, fmt.Errorf("Could not bind group snapshot %s and group snapshot content %s, the VolumeGroupSnapshotRef does not match", groupSnapshot.Name, groupSnapshotContent.Name) + return nil, fmt.Errorf("could not bind group snapshot %s and group snapshot content %s, the VolumeGroupSnapshotRef does not match", groupSnapshot.Name, groupSnapshotContent.Name) } else if groupSnapshotContent.Spec.VolumeGroupSnapshotRef.UID != "" && groupSnapshotContent.Spec.VolumeGroupSnapshotRef.UID != groupSnapshot.UID { - return nil, fmt.Errorf("Could not bind group snapshot %s and group snapshot content %s, the VolumeGroupSnapshotRef does not match", groupSnapshot.Name, groupSnapshotContent.Name) + return nil, fmt.Errorf("could not bind group snapshot %s and group snapshot content %s, the VolumeGroupSnapshotRef does not match", groupSnapshot.Name, groupSnapshotContent.Name) } else if groupSnapshotContent.Spec.VolumeGroupSnapshotRef.UID != "" && groupSnapshotContent.Spec.VolumeGroupSnapshotClassName != nil { return groupSnapshotContent, nil } @@ -1177,7 +1177,7 @@ func (ctrl *csiSnapshotCommonController) syncGroupSnapshotContent(groupSnapshotC if (groupSnapshotContent.Spec.Source.GroupSnapshotHandles == nil && len(groupSnapshotContent.Spec.Source.VolumeHandles) == 0) || (groupSnapshotContent.Spec.Source.GroupSnapshotHandles != nil && len(groupSnapshotContent.Spec.Source.VolumeHandles) > 0) { - err := fmt.Errorf("Exactly one of GroupSnapshotHandles and VolumeHandles should be specified") + err := fmt.Errorf("exactly one of GroupSnapshotHandles and VolumeHandles should be specified") klog.Errorf("syncGroupSnapshotContent[%s]: validation error, %s", groupSnapshotContent.Name, err.Error()) ctrl.eventRecorder.Event(groupSnapshotContent, v1.EventTypeWarning, "GroupContentValidationError", err.Error()) return err @@ -1415,11 +1415,11 @@ func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimesta groupSnapshotContentName = *groupSnapshot.Status.BoundVolumeGroupSnapshotContentName } // for a dynamically created group snapshot, it's possible that a group snapshot - // content has been created however the Status of the group snapshot has not + // content has been created even though the Status of the group snapshot has not // been updated yet, i.e., failed right after group snapshot content creation. // In this case, use the fixed naming scheme to get the group snapshot content // name and search - if groupSnapshotContentName == "" && &groupSnapshot.Spec.Source.VolumeGroupSnapshotContentName == nil { + if groupSnapshotContentName == "" && groupSnapshot.Spec.Source.VolumeGroupSnapshotContentName == nil { groupSnapshotContentName = utils.GetDynamicSnapshotContentNameForGroupSnapshot(groupSnapshot) } // find a group snapshot content from cache store, note that it's completely legit @@ -1451,7 +1451,7 @@ func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimesta return nil } - // Look up for members of this volume group snapshot + // Look for members of this volume group snapshot snapshotMembers, err := ctrl.findGroupSnapshotMembers( types.NamespacedName{ Name: groupSnapshot.Name, @@ -1520,7 +1520,7 @@ func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimesta for _, snapshot := range snapshotMembers { err := ctrl.clientset.SnapshotV1(). VolumeSnapshots(groupSnapshot.Namespace). - Delete(context.TODO(), snapshot.Name, metav1.DeleteOptions{}) + Delete(ctx, snapshot.Name, metav1.DeleteOptions{}) if err != nil && !apierrs.IsNotFound(err) { msg := fmt.Sprintf( "failed to delete snapshot API object %s/%s part of group snapshot %s: %v", diff --git a/pkg/common-controller/snapshot_controller.go b/pkg/common-controller/snapshot_controller.go index 732e617d5..d87feea9b 100644 --- a/pkg/common-controller/snapshot_controller.go +++ b/pkg/common-controller/snapshot_controller.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "slices" - "strings" "time" v1 "k8s.io/api/core/v1" @@ -95,7 +94,7 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh if (content.Spec.Source.VolumeHandle == nil && content.Spec.Source.SnapshotHandle == nil) || (content.Spec.Source.VolumeHandle != nil && content.Spec.Source.SnapshotHandle != nil) { - err := fmt.Errorf("Exactly one of VolumeHandle and SnapshotHandle should be specified") + err := fmt.Errorf("exactly one of VolumeHandle and SnapshotHandle should be specified") klog.Errorf("syncContent[%s]: validation error, %s", content.Name, err.Error()) ctrl.eventRecorder.Event(content, v1.EventTypeWarning, "ContentValidationError", err.Error()) return err @@ -196,7 +195,7 @@ func (ctrl *csiSnapshotCommonController) syncSnapshot(ctx context.Context, snaps klog.V(5).Infof("syncSnapshot[%s]: validate snapshot to make sure source has been correctly specified", utils.SnapshotKey(snapshot)) if (snapshot.Spec.Source.PersistentVolumeClaimName == nil && snapshot.Spec.Source.VolumeSnapshotContentName == nil) || (snapshot.Spec.Source.PersistentVolumeClaimName != nil && snapshot.Spec.Source.VolumeSnapshotContentName != nil) { - err := fmt.Errorf("Exactly one of PersistentVolumeClaimName and VolumeSnapshotContentName should be specified") + err := fmt.Errorf("exactly one of PersistentVolumeClaimName and VolumeSnapshotContentName should be specified") klog.Errorf("syncSnapshot[%s]: validation error, %s", utils.SnapshotKey(snapshot), err.Error()) ctrl.updateSnapshotErrorStatusWithEvent(snapshot, true, v1.EventTypeWarning, "SnapshotValidationError", err.Error()) return err @@ -856,11 +855,11 @@ func (ctrl *csiSnapshotCommonController) getCreateSnapshotInput(snapshot *crdv1. return class, volume, contentName, snapshotterSecretRef, nil } -func (ctrl *csiSnapshotCommonController) storeSnapshotUpdate(snapshot interface{}) (bool, error) { +func (ctrl *csiSnapshotCommonController) storeSnapshotUpdate(snapshot any) (bool, error) { return utils.StoreObjectUpdate(ctrl.snapshotStore, snapshot, "snapshot") } -func (ctrl *csiSnapshotCommonController) storeContentUpdate(content interface{}) (bool, error) { +func (ctrl *csiSnapshotCommonController) storeContentUpdate(content any) (bool, error) { return utils.StoreObjectUpdate(ctrl.contentStore, content, "content") } @@ -1102,9 +1101,9 @@ func (ctrl *csiSnapshotCommonController) checkandRemovePVCFinalizer(snapshot *cr // in content.Spec.VolumeSnapshotRef. func (ctrl *csiSnapshotCommonController) checkandBindSnapshotContent(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent) (*crdv1.VolumeSnapshotContent, error) { if content.Spec.VolumeSnapshotRef.Name != snapshot.Name { - return nil, fmt.Errorf("Could not bind snapshot %s and content %s, the VolumeSnapshotRef does not match", snapshot.Name, content.Name) + return nil, fmt.Errorf("could not bind snapshot %s and content %s, the VolumeSnapshotRef does not match", snapshot.Name, content.Name) } else if content.Spec.VolumeSnapshotRef.UID != "" && content.Spec.VolumeSnapshotRef.UID != snapshot.UID { - return nil, fmt.Errorf("Could not bind snapshot %s and content %s, the VolumeSnapshotRef does not match", snapshot.Name, content.Name) + return nil, fmt.Errorf("could not bind snapshot %s and content %s, the VolumeSnapshotRef does not match", snapshot.Name, content.Name) } else if content.Spec.VolumeSnapshotRef.UID != "" && content.Spec.VolumeSnapshotClassName != nil { return content, nil } @@ -1362,7 +1361,7 @@ func (ctrl *csiSnapshotCommonController) getVolumeFromVolumeSnapshot(snapshot *c // Verify binding between PV/PVC is still valid bound := ctrl.isVolumeBoundToClaim(pv, pvc) - if bound == false { + if !bound { klog.Warningf("binding between PV %s and PVC %s is broken", pvName, pvc.Name) return nil, fmt.Errorf("claim in dataSource not bound or invalid") } @@ -1558,15 +1557,6 @@ func (e controllerUpdateError) Error() string { return e.message } -func isControllerUpdateFailError(err *crdv1.VolumeSnapshotError) bool { - if err != nil { - if strings.Contains(*err.Message, controllerUpdateFailMsg) { - return true - } - } - return false -} - // addSnapshotFinalizer adds a Finalizer for VolumeSnapshot. func (ctrl *csiSnapshotCommonController) addSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot, addSourceFinalizer bool, addBoundFinalizer bool) error { var updatedSnapshot *crdv1.VolumeSnapshot diff --git a/pkg/common-controller/snapshot_controller_base.go b/pkg/common-controller/snapshot_controller_base.go index fcd65b3ae..a7d285e89 100644 --- a/pkg/common-controller/snapshot_controller_base.go +++ b/pkg/common-controller/snapshot_controller_base.go @@ -120,8 +120,7 @@ func NewCSISnapshotCommonController( broadcaster := record.NewBroadcaster() broadcaster.StartLogging(klog.Infof) broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: client.CoreV1().Events(v1.NamespaceAll)}) - var eventRecorder record.EventRecorder - eventRecorder = broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("snapshot-controller")}) + var eventRecorder record.EventRecorder = broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "snapshot-controller"}) ctrl := &csiSnapshotCommonController{ clientset: clientset, @@ -146,7 +145,7 @@ func NewCSISnapshotCommonController( ctrl.pvListerSynced = pvInformer.Informer().HasSynced pvInformer.Informer().AddIndexers(map[string]cache.IndexFunc{ - utils.CSIDriverHandleIndexName: func(obj interface{}) ([]string, error) { + utils.CSIDriverHandleIndexName: func(obj any) ([]string, error) { if pv, ok := obj.(*v1.PersistentVolume); ok { if key := utils.PersistentVolumeKeyFunc(pv); key != "" { return []string{key}, nil @@ -160,14 +159,14 @@ func NewCSISnapshotCommonController( volumeSnapshotInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { ctrl.enqueueSnapshotWork(obj) }, - UpdateFunc: func(oldObj, newObj interface{}) { ctrl.enqueueSnapshotWork(newObj) }, - DeleteFunc: func(obj interface{}) { ctrl.enqueueSnapshotWork(obj) }, + AddFunc: func(obj any) { ctrl.enqueueSnapshotWork(obj) }, + UpdateFunc: func(oldObj, newObj any) { ctrl.enqueueSnapshotWork(newObj) }, + DeleteFunc: func(obj any) { ctrl.enqueueSnapshotWork(obj) }, }, ctrl.resyncPeriod, ) volumeSnapshotInformer.Informer().AddIndexers(map[string]cache.IndexFunc{ - utils.VolumeSnapshotParentGroupIndex: func(obj interface{}) ([]string, error) { + utils.VolumeSnapshotParentGroupIndex: func(obj any) ([]string, error) { if snapshot, ok := obj.(*crdv1.VolumeSnapshot); ok { if key := utils.VolumeSnapshotParentGroupKeyFunc(snapshot); key != "" { return []string{key}, nil @@ -183,9 +182,9 @@ func NewCSISnapshotCommonController( volumeSnapshotContentInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { ctrl.enqueueContentWork(obj) }, - UpdateFunc: func(oldObj, newObj interface{}) { ctrl.enqueueContentWork(newObj) }, - DeleteFunc: func(obj interface{}) { ctrl.enqueueContentWork(obj) }, + AddFunc: func(obj any) { ctrl.enqueueContentWork(obj) }, + UpdateFunc: func(oldObj, newObj any) { ctrl.enqueueContentWork(newObj) }, + DeleteFunc: func(obj any) { ctrl.enqueueContentWork(obj) }, }, ctrl.resyncPeriod, ) @@ -219,9 +218,9 @@ func NewCSISnapshotCommonController( volumeGroupSnapshotInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { ctrl.enqueueGroupSnapshotWork(obj) }, - UpdateFunc: func(oldObj, newObj interface{}) { ctrl.enqueueGroupSnapshotWork(newObj) }, - DeleteFunc: func(obj interface{}) { ctrl.enqueueGroupSnapshotWork(obj) }, + AddFunc: func(obj any) { ctrl.enqueueGroupSnapshotWork(obj) }, + UpdateFunc: func(oldObj, newObj any) { ctrl.enqueueGroupSnapshotWork(newObj) }, + DeleteFunc: func(obj any) { ctrl.enqueueGroupSnapshotWork(obj) }, }, ctrl.resyncPeriod, ) @@ -230,9 +229,9 @@ func NewCSISnapshotCommonController( volumeGroupSnapshotContentInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { ctrl.enqueueGroupSnapshotContentWork(obj) }, - UpdateFunc: func(oldObj, newObj interface{}) { ctrl.enqueueGroupSnapshotContentWork(newObj) }, - DeleteFunc: func(obj interface{}) { ctrl.enqueueGroupSnapshotContentWork(obj) }, + AddFunc: func(obj any) { ctrl.enqueueGroupSnapshotContentWork(obj) }, + UpdateFunc: func(oldObj, newObj any) { ctrl.enqueueGroupSnapshotContentWork(newObj) }, + DeleteFunc: func(obj any) { ctrl.enqueueGroupSnapshotContentWork(obj) }, }, ctrl.resyncPeriod, ) @@ -280,7 +279,7 @@ func (ctrl *csiSnapshotCommonController) Run(workers int, stopCh <-chan struct{} ctrl.initializeCaches() if utilfeature.DefaultFeatureGate.Enabled(features.ReleaseLeaderElectionOnExit) { - for i := 0; i < workers; i++ { + for range workers { wg.Add(1) go func() { defer wg.Done() @@ -306,7 +305,7 @@ func (ctrl *csiSnapshotCommonController) Run(workers int, stopCh <-chan struct{} } } } else { - for i := 0; i < workers; i++ { + for range workers { go wait.Until(ctrl.snapshotWorker, 0, stopCh) go wait.Until(ctrl.contentWorker, 0, stopCh) if ctrl.enableVolumeGroupSnapshots { @@ -320,7 +319,7 @@ func (ctrl *csiSnapshotCommonController) Run(workers int, stopCh <-chan struct{} } // enqueueSnapshotWork adds snapshot to given work queue. -func (ctrl *csiSnapshotCommonController) enqueueSnapshotWork(obj interface{}) { +func (ctrl *csiSnapshotCommonController) enqueueSnapshotWork(obj any) { // Beware of "xxx deleted" events if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil { obj = unknown.Obj @@ -337,7 +336,7 @@ func (ctrl *csiSnapshotCommonController) enqueueSnapshotWork(obj interface{}) { } // enqueueContentWork adds snapshot content to given work queue. -func (ctrl *csiSnapshotCommonController) enqueueContentWork(obj interface{}) { +func (ctrl *csiSnapshotCommonController) enqueueContentWork(obj any) { // Beware of "xxx deleted" events if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil { obj = unknown.Obj @@ -401,7 +400,7 @@ func (ctrl *csiSnapshotCommonController) syncSnapshotByKey(key string) error { } return err } - if err != nil && !errors.IsNotFound(err) { + if !errors.IsNotFound(err) { klog.V(2).Infof("error getting snapshot %q from informer: %v", key, err) return err } @@ -684,7 +683,7 @@ func (ctrl *csiSnapshotCommonController) initializeCaches() { } // enqueueGroupSnapshotWork adds group snapshot to given work queue. -func (ctrl *csiSnapshotCommonController) enqueueGroupSnapshotWork(obj interface{}) { +func (ctrl *csiSnapshotCommonController) enqueueGroupSnapshotWork(obj any) { // Beware of "xxx deleted" events if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil { obj = unknown.Obj @@ -701,7 +700,7 @@ func (ctrl *csiSnapshotCommonController) enqueueGroupSnapshotWork(obj interface{ } // enqueueGroupSnapshotContentWork adds group snapshot content to given work queue. -func (ctrl *csiSnapshotCommonController) enqueueGroupSnapshotContentWork(obj interface{}) { +func (ctrl *csiSnapshotCommonController) enqueueGroupSnapshotContentWork(obj any) { // Beware of "xxx deleted" events if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil { obj = unknown.Obj @@ -784,7 +783,7 @@ func (ctrl *csiSnapshotCommonController) syncGroupSnapshotByKey(ctx context.Cont } return err } - if err != nil && !errors.IsNotFound(err) { + if !errors.IsNotFound(err) { klog.V(2).Infof("error getting group snapshot %q from informer: %v", key, err) return err } diff --git a/pkg/common-controller/snapshot_create_test.go b/pkg/common-controller/snapshot_create_test.go index 8485635ae..a5ae5a04d 100644 --- a/pkg/common-controller/snapshot_create_test.go +++ b/pkg/common-controller/snapshot_create_test.go @@ -23,7 +23,6 @@ import ( crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var ( @@ -33,14 +32,9 @@ var ( True = true ) -var metaTimeNowUnix = &metav1.Time{ - Time: timeNow, -} - var ( - defaultSize int64 = 1000 - deletePolicy = crdv1.VolumeSnapshotContentDelete - retainPolicy = crdv1.VolumeSnapshotContentRetain + deletePolicy = crdv1.VolumeSnapshotContentDelete + retainPolicy = crdv1.VolumeSnapshotContentRetain ) // Test single call to SyncSnapshot, expecting create snapshot to happen. diff --git a/pkg/common-controller/snapshot_delete_test.go b/pkg/common-controller/snapshot_delete_test.go index 2474a11f7..80035fa7e 100644 --- a/pkg/common-controller/snapshot_delete_test.go +++ b/pkg/common-controller/snapshot_delete_test.go @@ -51,11 +51,6 @@ var class5Parameters = map[string]string{ var timeNowMetav1 = metav1.Now() -var ( - content31 = "content3-1" - claim31 = "claim3-1" -) - var snapshotClasses = []*crdv1.VolumeSnapshotClass{ { TypeMeta: metav1.TypeMeta{ diff --git a/pkg/common-controller/snapshot_update_test.go b/pkg/common-controller/snapshot_update_test.go index 9ea063e4d..1c03d126b 100644 --- a/pkg/common-controller/snapshot_update_test.go +++ b/pkg/common-controller/snapshot_update_test.go @@ -31,8 +31,6 @@ var metaTimeNow = &metav1.Time{ Time: time.Now(), } -var emptyString = "" - // Test single call to syncSnapshot and syncContent methods. // 1. Fill in the controller with initial data // 2. Call the tested function (syncSnapshot/syncContent) via diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go index bd0883e52..dafd4e6de 100644 --- a/pkg/metrics/metrics_test.go +++ b/pkg/metrics/metrics_test.go @@ -303,10 +303,10 @@ func TestConcurrency(t *testing.T) { statusCode: 1, } ops := []struct { - op OperationKey - desiredLatencyMs time.Duration - status OperationStatus - drop bool + op OperationKey + desiredLatency time.Duration + status OperationStatus + drop bool }{ { OperationKey{ @@ -386,8 +386,8 @@ func TestConcurrency(t *testing.T) { wgMetrics.Add(1) go func(i int) { defer wgMetrics.Done() - if ops[i].desiredLatencyMs > 0 { - time.Sleep(ops[i].desiredLatencyMs * time.Millisecond) + if ops[i].desiredLatency > 0 { + time.Sleep(ops[i].desiredLatency * time.Millisecond) } if ops[i].drop { mgr.DropOperation(ops[i].op) @@ -530,7 +530,7 @@ func TestInFlightMetric(t *testing.T) { } // Start 50 operations, should be 51 - for i := 0; i < 50; i++ { + for i := range 50 { opKey := OperationKey{ Name: fmt.Sprintf("op%d", i), ResourceID: types.UID("uid%d"), @@ -657,7 +657,7 @@ func containsMetrics(expectedMfs, gotMfs []*cmg.MetricFamily) bool { return false } for i := 0; i < len(got.Metric); i++ { - for j := 0; j < numRecords; j++ { + for j := range numRecords { if got.Metric[i].Histogram == nil && expected.Metric[j].Histogram != nil || got.Metric[i].Histogram != nil && expected.Metric[j].Histogram == nil { fmt.Printf("got metric and expected metric histogram type mismatch") diff --git a/pkg/sidecar-controller/csi_handler.go b/pkg/sidecar-controller/csi_handler.go index 9658e3179..78169afdc 100644 --- a/pkg/sidecar-controller/csi_handler.go +++ b/pkg/sidecar-controller/csi_handler.go @@ -139,7 +139,7 @@ func makeSnapshotName(prefix, snapshotUID string, snapshotNameUUIDLength int) (s // create persistent name based on a volumeNamePrefix and volumeNameUUIDLength // of PVC's UID if len(snapshotUID) == 0 { - return "", fmt.Errorf("Corrupted snapshot object, it is missing UID") + return "", fmt.Errorf("corrupted snapshot object, it is missing UID") } if snapshotNameUUIDLength == -1 { // Default behavior is to not truncate or remove dashes diff --git a/pkg/sidecar-controller/framework_test.go b/pkg/sidecar-controller/framework_test.go index a8bf8b74a..2be021b0e 100644 --- a/pkg/sidecar-controller/framework_test.go +++ b/pkg/sidecar-controller/framework_test.go @@ -36,7 +36,6 @@ import ( storagelisters "github.com/kubernetes-csi/external-snapshotter/client/v8/listers/volumesnapshot/v1" "github.com/kubernetes-csi/external-snapshotter/v8/pkg/utils" v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -134,7 +133,7 @@ type snapshotReactor struct { secrets map[string]*v1.Secret snapshotClasses map[string]*crdv1.VolumeSnapshotClass contents map[string]*crdv1.VolumeSnapshotContent - changedObjects []interface{} + changedObjects []any changedSinceLastSync int ctrl *csiSnapshotSideCarController fakeContentWatch *watch.FakeWatcher @@ -387,7 +386,7 @@ func checkEvents(t *testing.T, expectedEvents []string, ctrl *csiSnapshotSideCar klog.V(5).Infof("event recorder finished") finished = true } - case _, _ = <-timer.C: + case <-timer.C: klog.V(5).Infof("event recorder timeout") finished = true } @@ -413,51 +412,6 @@ func checkEvents(t *testing.T, expectedEvents []string, ctrl *csiSnapshotSideCar return err } -// popChange returns one recorded updated object, either *crdv1.VolumeSnapshotContent -// or *crdv1.VolumeSnapshot. Returns nil when there are no changes. -func (r *snapshotReactor) popChange() interface{} { - r.lock.Lock() - defer r.lock.Unlock() - - if len(r.changedObjects) == 0 { - return nil - } - - // For debugging purposes, print the queue - for _, obj := range r.changedObjects { - switch obj.(type) { - case *crdv1.VolumeSnapshotContent: - vol, _ := obj.(*crdv1.VolumeSnapshotContent) - klog.V(4).Infof("reactor queue: %s", vol.Name) - } - } - - // Pop the first item from the queue and return it - obj := r.changedObjects[0] - r.changedObjects = r.changedObjects[1:] - return obj -} - -// syncAll simulates the controller periodic sync of contents. It -// simply adds all these objects to the internal queue of updates. This method -// should be used when the test manually calls syncContent. Test that -// use real controller loop (ctrl.Run()) will get periodic sync automatically. -func (r *snapshotReactor) syncAll() { - r.lock.Lock() - defer r.lock.Unlock() - - for _, v := range r.contents { - r.changedObjects = append(r.changedObjects, v) - } - r.changedSinceLastSync = 0 -} - -func (r *snapshotReactor) getChangeCount() int { - r.lock.Lock() - defer r.lock.Unlock() - return r.changedSinceLastSync -} - // waitTest waits until all tests, controllers and other goroutines do their // job and list of current contents/snapshots is equal to list of expected // contents/snapshots (with ~10 second timeout). @@ -480,51 +434,7 @@ func (r *snapshotReactor) waitTest(test controllerTest) error { return err } -// deleteContentEvent simulates that a content has been deleted in etcd and -// the controller receives 'content deleted' event. -func (r *snapshotReactor) deleteContentEvent(content *crdv1.VolumeSnapshotContent) { - r.lock.Lock() - defer r.lock.Unlock() - - // Remove the content from list of resulting contents. - delete(r.contents, content.Name) - - // Generate deletion event. Cloned content is needed to prevent races (and we - // would get a clone from etcd too). - if r.fakeContentWatch != nil { - r.fakeContentWatch.Delete(content.DeepCopy()) - } -} - -// addContentEvent simulates that a content has been added in etcd and the -// controller receives 'content added' event. -func (r *snapshotReactor) addContentEvent(content *crdv1.VolumeSnapshotContent) { - r.lock.Lock() - defer r.lock.Unlock() - - r.contents[content.Name] = content - // Generate event. No cloning is needed, this snapshot is not stored in the - // controller cache yet. - if r.fakeContentWatch != nil { - r.fakeContentWatch.Add(content) - } -} - -// modifyContentEvent simulates that a content has been modified in etcd and the -// controller receives 'content modified' event. -func (r *snapshotReactor) modifyContentEvent(content *crdv1.VolumeSnapshotContent) { - r.lock.Lock() - defer r.lock.Unlock() - - r.contents[content.Name] = content - // Generate deletion event. Cloned content is needed to prevent races (and we - // would get a clone from etcd too). - if r.fakeContentWatch != nil { - r.fakeContentWatch.Modify(content.DeepCopy()) - } -} - -func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset, ctrl *csiSnapshotSideCarController, fakeVolumeWatch, fakeClaimWatch *watch.FakeWatcher, errors []reactorError) *snapshotReactor { +func newSnapshotReactor(kubeClient *kubefake.Clientset, client *fake.Clientset, ctrl *csiSnapshotSideCarController, fakeVolumeWatch *watch.FakeWatcher, errors []reactorError) *snapshotReactor { reactor := &snapshotReactor{ secrets: make(map[string]*v1.Secret), snapshotClasses: make(map[string]*crdv1.VolumeSnapshotClass), @@ -704,28 +614,13 @@ func testSyncContent(ctrl *csiSnapshotSideCarController, reactor *snapshotReacto return ctrl.syncContent(test.initialContents[0]) } -func testSyncContentError(ctrl *csiSnapshotSideCarController, reactor *snapshotReactor, test controllerTest) (bool, error) { - requeue, err := ctrl.syncContent(test.initialContents[0]) - if err != nil { - return requeue, nil - } - return requeue, fmt.Errorf("syncSnapshotContent succeeded when failure was expected") -} - var ( - classEmpty string classGold = "gold" classSilver = "silver" - classNonExisting = "non-existing" defaultClass = "default-class" emptySecretClass = "empty-secret-class" invalidSecretClass = "invalid-secret-class" validSecretClass = "valid-secret-class" - sameDriver = "sameDriver" - diffDriver = "diffDriver" - noClaim = "" - noBoundUID = "" - noVolume = "" ) // wrapTestWithInjectedOperation returns a testCall that: @@ -794,7 +689,7 @@ func runSyncContentTests(t *testing.T, tests []controllerTest, snapshotClasses [ t.Fatalf("Test %q construct persistent content failed: %v", test.name, err) } - reactor := newSnapshotReactor(kubeClient, client, ctrl, nil, nil, test.errors) + reactor := newSnapshotReactor(kubeClient, client, ctrl, nil, test.errors) for _, content := range test.initialContents { if ctrl.isDriverMatch(test.initialContents[0]) { ctrl.contentStore.Add(content) @@ -840,19 +735,6 @@ func runSyncContentTests(t *testing.T, tests []controllerTest, snapshotClasses [ } } -func getSize(size int64) *resource.Quantity { - return resource.NewQuantity(size, resource.BinarySI) -} - -func emptySecret() *v1.Secret { - return &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "emptysecret", - Namespace: "default", - }, - } -} - func secret() *v1.Secret { return &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -865,28 +747,6 @@ func secret() *v1.Secret { } } -func secretAnnotations() map[string]string { - return map[string]string{ - utils.AnnDeletionSecretRefName: "secret", - utils.AnnDeletionSecretRefNamespace: "default", - } -} - -func emptyNamespaceSecretAnnotations() map[string]string { - return map[string]string{ - utils.AnnDeletionSecretRefName: "name", - utils.AnnDeletionSecretRefNamespace: "", - } -} - -// this refers to emptySecret(), which is missing data. -func emptyDataSecretAnnotations() map[string]string { - return map[string]string{ - utils.AnnDeletionSecretRefName: "emptysecret", - utils.AnnDeletionSecretRefNamespace: "default", - } -} - type listCall struct { snapshotID string secrets map[string]string diff --git a/pkg/sidecar-controller/groupsnapshot_helper.go b/pkg/sidecar-controller/groupsnapshot_helper.go index 70512ea83..ca8b85274 100644 --- a/pkg/sidecar-controller/groupsnapshot_helper.go +++ b/pkg/sidecar-controller/groupsnapshot_helper.go @@ -20,6 +20,7 @@ import ( "context" "crypto/sha256" "fmt" + "maps" "slices" "strings" "time" @@ -43,12 +44,12 @@ type snapshotContentNameVolumeHandlePair struct { volumeHandle string } -func (ctrl *csiSnapshotSideCarController) storeGroupSnapshotContentUpdate(groupSnapshotContent interface{}) (bool, error) { +func (ctrl *csiSnapshotSideCarController) storeGroupSnapshotContentUpdate(groupSnapshotContent any) (bool, error) { return utils.StoreObjectUpdate(ctrl.groupSnapshotContentStore, groupSnapshotContent, "groupsnapshotcontent") } // enqueueGroupSnapshotContentWork adds group snapshot content to given work queue. -func (ctrl *csiSnapshotSideCarController) enqueueGroupSnapshotContentWork(obj interface{}) { +func (ctrl *csiSnapshotSideCarController) enqueueGroupSnapshotContentWork(obj any) { // Beware of "xxx deleted" events if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil { obj = unknown.Obj @@ -84,7 +85,6 @@ func (ctrl *csiSnapshotSideCarController) groupSnapshotContentWorker() { // Finally, if no error occurs we forget this item so it does not // get queued again until another change happens. ctrl.groupSnapshotContentQueue.Forget(key) - return } func (ctrl *csiSnapshotSideCarController) syncGroupSnapshotContentByKey(key string) error { @@ -200,7 +200,7 @@ func (ctrl *csiSnapshotSideCarController) syncGroupSnapshotContent(groupSnapshot // true. We don't want to keep calling CreateGroupSnapshot CSI methods over // and over again for performance reasons. var err error - if groupSnapshotContent.Status != nil && groupSnapshotContent.Status.ReadyToUse != nil && *groupSnapshotContent.Status.ReadyToUse == true { + if groupSnapshotContent.Status != nil && groupSnapshotContent.Status.ReadyToUse != nil && *groupSnapshotContent.Status.ReadyToUse { // Try to remove AnnVolumeGroupSnapshotBeingCreated if it is not removed yet for some reason _, err = ctrl.removeAnnVolumeGroupSnapshotBeingCreated(groupSnapshotContent) return err @@ -520,9 +520,7 @@ func (ctrl *csiSnapshotSideCarController) setAnnVolumeGroupSnapshotBeingCreated( // If there are no existing annotations, we create a new map. klog.V(5).Infof("setAnnVolumeGroupSnapshotBeingCreated: set annotation [%s:yes] on groupSnapshotContent [%s].", utils.AnnVolumeGroupSnapshotBeingCreated, groupSnapshotContent.Name) patchedAnnotations := make(map[string]string) - for k, v := range groupSnapshotContent.GetAnnotations() { - patchedAnnotations[k] = v - } + maps.Copy(patchedAnnotations, groupSnapshotContent.GetAnnotations()) patchedAnnotations[utils.AnnVolumeGroupSnapshotBeingCreated] = "yes" var patches []utils.PatchOp diff --git a/pkg/sidecar-controller/snapshot_controller.go b/pkg/sidecar-controller/snapshot_controller.go index 73b8a2c88..2136ceb50 100644 --- a/pkg/sidecar-controller/snapshot_controller.go +++ b/pkg/sidecar-controller/snapshot_controller.go @@ -19,6 +19,7 @@ package sidecar_controller import ( "context" "fmt" + "maps" "slices" "strings" "time" @@ -114,7 +115,7 @@ func (ctrl *csiSnapshotSideCarController) deleteCSISnapshot(content *crdv1.Volum return ctrl.deleteCSISnapshotOperation(content) } -func (ctrl *csiSnapshotSideCarController) storeContentUpdate(content interface{}) (bool, error) { +func (ctrl *csiSnapshotSideCarController) storeContentUpdate(content any) (bool, error) { return utils.StoreObjectUpdate(ctrl.contentStore, content, "content") } @@ -561,15 +562,6 @@ func (e controllerUpdateError) Error() string { return e.message } -func isControllerUpdateFailError(err *crdv1.VolumeSnapshotError) bool { - if err != nil { - if strings.Contains(*err.Message, controllerUpdateFailMsg) { - return true - } - } - return false -} - func (ctrl *csiSnapshotSideCarController) GetCredentialsFromAnnotation(content *crdv1.VolumeSnapshotContent) (map[string]string, error) { // get secrets if VolumeSnapshotClass specifies it var snapshotterCredentials map[string]string @@ -673,9 +665,7 @@ func (ctrl *csiSnapshotSideCarController) setAnnVolumeSnapshotBeingCreated(conte // If there are no existing annotations, we create a new map. klog.V(5).Infof("setAnnVolumeSnapshotBeingCreated: set annotation [%s:yes] on content [%s].", utils.AnnVolumeSnapshotBeingCreated, content.Name) patchedAnnotations := make(map[string]string) - for k, v := range content.GetAnnotations() { - patchedAnnotations[k] = v - } + maps.Copy(patchedAnnotations, content.GetAnnotations()) patchedAnnotations[utils.AnnVolumeSnapshotBeingCreated] = "yes" var patches []utils.PatchOp diff --git a/pkg/sidecar-controller/snapshot_controller_base.go b/pkg/sidecar-controller/snapshot_controller_base.go index d25b0bb99..989465f1a 100644 --- a/pkg/sidecar-controller/snapshot_controller_base.go +++ b/pkg/sidecar-controller/snapshot_controller_base.go @@ -101,8 +101,7 @@ func NewCSISnapshotSideCarController( broadcaster := record.NewBroadcaster() broadcaster.StartLogging(klog.Infof) broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: client.CoreV1().Events(v1.NamespaceAll)}) - var eventRecorder record.EventRecorder - eventRecorder = broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("csi-snapshotter %s", driverName)}) + var eventRecorder record.EventRecorder = broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("csi-snapshotter %s", driverName)}) ctrl := &csiSnapshotSideCarController{ clientset: clientset, @@ -120,15 +119,15 @@ func NewCSISnapshotSideCarController( volumeSnapshotContentInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { ctrl.enqueueContentWork(obj) }, - UpdateFunc: func(oldObj, newObj interface{}) { + AddFunc: func(obj any) { ctrl.enqueueContentWork(obj) }, + UpdateFunc: func(oldObj, newObj any) { // Only enqueue updated VolumeSnapshotContent object if it contains a change that may need resync // Ignore changes that cannot necessitate a sync and/or are caused by the sidecar itself if utils.ShouldEnqueueContentChange(oldObj.(*crdv1.VolumeSnapshotContent), newObj.(*crdv1.VolumeSnapshotContent)) { ctrl.enqueueContentWork(newObj) } }, - DeleteFunc: func(obj interface{}) { ctrl.enqueueContentWork(obj) }, + DeleteFunc: func(obj any) { ctrl.enqueueContentWork(obj) }, }, ctrl.resyncPeriod, ) @@ -147,14 +146,14 @@ func NewCSISnapshotSideCarController( volumeGroupSnapshotContentInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { ctrl.enqueueGroupSnapshotContentWork(obj) }, - UpdateFunc: func(oldObj, newObj interface{}) { + AddFunc: func(obj any) { ctrl.enqueueGroupSnapshotContentWork(obj) }, + UpdateFunc: func(oldObj, newObj any) { /* TODO: Determine if we need to skip requeueing in case of CSI driver failure. */ ctrl.enqueueGroupSnapshotContentWork(newObj) }, - DeleteFunc: func(obj interface{}) { ctrl.enqueueGroupSnapshotContentWork(obj) }, + DeleteFunc: func(obj any) { ctrl.enqueueGroupSnapshotContentWork(obj) }, }, ctrl.resyncPeriod, ) @@ -189,7 +188,7 @@ func (ctrl *csiSnapshotSideCarController) Run(workers int, stopCh <-chan struct{ ctrl.initializeCaches() if utilfeature.DefaultFeatureGate.Enabled(features.ReleaseLeaderElectionOnExit) { - for i := 0; i < workers; i++ { + for range workers { wg.Add(1) go func() { defer wg.Done() @@ -204,7 +203,7 @@ func (ctrl *csiSnapshotSideCarController) Run(workers int, stopCh <-chan struct{ } } } else { - for i := 0; i < workers; i++ { + for range workers { go wait.Until(ctrl.contentWorker, 0, stopCh) if ctrl.enableVolumeGroupSnapshots { go wait.Until(ctrl.groupSnapshotContentWorker, 0, stopCh) @@ -216,7 +215,7 @@ func (ctrl *csiSnapshotSideCarController) Run(workers int, stopCh <-chan struct{ } // enqueueContentWork adds snapshot content to given work queue. -func (ctrl *csiSnapshotSideCarController) enqueueContentWork(obj interface{}) { +func (ctrl *csiSnapshotSideCarController) enqueueContentWork(obj any) { // Beware of "xxx deleted" events if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil { obj = unknown.Obj @@ -333,7 +332,7 @@ func (ctrl *csiSnapshotSideCarController) syncContentByKey(key string) (requeue // isDriverMatch verifies whether the driver specified in VolumeSnapshotContent // or VolumeGroupSnapshotContent matches the controller's driver name -func (ctrl *csiSnapshotSideCarController) isDriverMatch(object interface{}) bool { +func (ctrl *csiSnapshotSideCarController) isDriverMatch(object any) bool { if content, ok := object.(*crdv1.VolumeSnapshotContent); ok { if content.Spec.Source.VolumeHandle == nil && content.Spec.Source.SnapshotHandle == nil { // Skip this snapshot content if it does not have a valid source diff --git a/pkg/sidecar-controller/snapshot_delete_test.go b/pkg/sidecar-controller/snapshot_delete_test.go index 4bb875924..d29eff3e1 100644 --- a/pkg/sidecar-controller/snapshot_delete_test.go +++ b/pkg/sidecar-controller/snapshot_delete_test.go @@ -30,14 +30,13 @@ import ( var ( defaultSize int64 = 1000 - emptySize int64 - deletePolicy = crdv1.VolumeSnapshotContentDelete - retainPolicy = crdv1.VolumeSnapshotContentRetain - timeNow = time.Now() - timeNowMetav1 = metav1.Now() - nonFractionalTime = metav1.NewTime(time.Now().Truncate(time.Second)) - False = false - True = true + deletePolicy = crdv1.VolumeSnapshotContentDelete + retainPolicy = crdv1.VolumeSnapshotContentRetain + timeNow = time.Now() + timeNowMetav1 = metav1.Now() + nonFractionalTime = metav1.NewTime(time.Now().Truncate(time.Second)) + False = false + True = true ) var class1Parameters = map[string]string{ @@ -49,28 +48,23 @@ var class2Parameters = map[string]string{ } var class3Parameters = map[string]string{ - "param3": "value3", - utils.AnnDeletionSecretRefName: "name", -} - -var class4Parameters = map[string]string{ utils.AnnDeletionSecretRefName: "emptysecret", utils.AnnDeletionSecretRefNamespace: "default", } -var class5Parameters = map[string]string{ +var class4Parameters = map[string]string{ utils.AnnDeletionSecretRefName: "secret", utils.AnnDeletionSecretRefNamespace: "default", } -var class6Parameters = map[string]string{ +var class5Parameters = map[string]string{ utils.PrefixedSnapshotterSecretNameKey: "secret", utils.PrefixedSnapshotterSecretNamespaceKey: "default", utils.PrefixedSnapshotterListSecretNameKey: "secret", utils.PrefixedSnapshotterListSecretNamespaceKey: "default", } -var class7Annotations = map[string]string{ +var class6Annotations = map[string]string{ utils.AnnDeletionSecretRefName: "secret-x", utils.AnnDeletionSecretRefNamespace: "default-x", } @@ -106,7 +100,7 @@ var snapshotClasses = []*crdv1.VolumeSnapshotClass{ Name: emptySecretClass, }, Driver: mockDriverName, - Parameters: class4Parameters, + Parameters: class3Parameters, DeletionPolicy: crdv1.VolumeSnapshotContentDelete, }, { @@ -115,7 +109,7 @@ var snapshotClasses = []*crdv1.VolumeSnapshotClass{ }, ObjectMeta: metav1.ObjectMeta{ Name: invalidSecretClass, - Annotations: class7Annotations, + Annotations: class6Annotations, }, Driver: mockDriverName, Parameters: class2Parameters, @@ -129,7 +123,7 @@ var snapshotClasses = []*crdv1.VolumeSnapshotClass{ Name: validSecretClass, }, Driver: mockDriverName, - Parameters: class5Parameters, + Parameters: class4Parameters, DeletionPolicy: crdv1.VolumeSnapshotContentDelete, }, { @@ -141,7 +135,7 @@ var snapshotClasses = []*crdv1.VolumeSnapshotClass{ Annotations: map[string]string{utils.IsDefaultSnapshotClassAnnotation: "true"}, }, Driver: mockDriverName, - Parameters: class6Parameters, + Parameters: class5Parameters, DeletionPolicy: crdv1.VolumeSnapshotContentDelete, }, } diff --git a/pkg/snapshotter/snapshotter.go b/pkg/snapshotter/snapshotter.go index 05f6fa660..5547e4bce 100644 --- a/pkg/snapshotter/snapshotter.go +++ b/pkg/snapshotter/snapshotter.go @@ -131,7 +131,7 @@ func (s *snapshot) GetSnapshotStatus(ctx context.Context, snapshotID string, sna return false, time.Time{}, 0, "", err } - if rsp.Entries == nil || len(rsp.Entries) == 0 { + if len(rsp.Entries) == 0 { return false, time.Time{}, 0, "", fmt.Errorf("can not find snapshot for snapshotID %s", snapshotID) } diff --git a/pkg/utils/patch.go b/pkg/utils/patch.go index 8f08d0bae..acb0101f3 100644 --- a/pkg/utils/patch.go +++ b/pkg/utils/patch.go @@ -13,9 +13,9 @@ import ( // PatchOp represents a json patch operation type PatchOp struct { - Op string `json:"op"` - Path string `json:"path"` - Value interface{} `json:"value,omitempty"` + Op string `json:"op"` + Path string `json:"path"` + Value any `json:"value,omitempty"` } // PatchVolumeSnapshotContent patches a volume snapshot content object diff --git a/pkg/utils/util.go b/pkg/utils/util.go index 7cdac6523..0e00db132 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -226,14 +226,14 @@ func SnapshotRefKey(vsref *v1.ObjectReference) string { // callback (i.e. with events from etcd) or with an object modified by the // controller itself. Returns "true", if the cache was updated, false if the // object is an old version and should be ignored. -func StoreObjectUpdate(store cache.Store, obj interface{}, className string) (bool, error) { +func StoreObjectUpdate(store cache.Store, obj any, className string) (bool, error) { objName, err := keyFunc(obj) if err != nil { - return false, fmt.Errorf("Couldn't get key for object %+v: %v", obj, err) + return false, fmt.Errorf("couldn't get key for object %+v: %v", obj, err) } oldObj, found, err := store.Get(obj) if err != nil { - return false, fmt.Errorf("Error finding %s %q in controller cache: %v", className, objName, err) + return false, fmt.Errorf("error finding %s %q in controller cache: %v", className, objName, err) } objAccessor, err := meta.Accessor(obj) @@ -533,22 +533,11 @@ func NeedToAddGroupSnapshotBoundFinalizer(groupSnapshot *crdv1beta2.VolumeGroupS return groupSnapshot.ObjectMeta.DeletionTimestamp == nil && !slices.Contains(groupSnapshot.ObjectMeta.Finalizers, VolumeGroupSnapshotBoundFinalizer) && IsBoundVolumeGroupSnapshotContentNameSet(groupSnapshot) } -func deprecationWarning(deprecatedParam, newParam, removalVersion string) string { - if removalVersion == "" { - removalVersion = "a future release" - } - newParamPhrase := "" - if len(newParam) != 0 { - newParamPhrase = fmt.Sprintf(", please use \"%s\" instead", newParam) - } - return fmt.Sprintf("\"%s\" is deprecated and will be removed in %s%s", deprecatedParam, removalVersion, newParamPhrase) -} - func RemovePrefixedParameters(param map[string]string) (map[string]string, error) { newParam := map[string]string{} for k, v := range param { if strings.HasPrefix(k, csiParameterPrefix) { - // Check if its well known + // Check if it's well known switch k { case PrefixedSnapshotterSecretNameKey: case PrefixedSnapshotterSecretNamespaceKey: @@ -580,7 +569,7 @@ func GetSnapshotStatusForLogging(snapshot *crdv1.VolumeSnapshot) string { if snapshot.Status != nil && snapshot.Status.ReadyToUse != nil { ready = *snapshot.Status.ReadyToUse } - return fmt.Sprintf("bound to: %q, Completed: %v", snapshotContentName, ready) + return fmt.Sprintf("bound to: %q, completed: %v", snapshotContentName, ready) } func GetGroupSnapshotStatusForLogging(groupSnapshot *crdv1beta2.VolumeGroupSnapshot) string { @@ -592,7 +581,7 @@ func GetGroupSnapshotStatusForLogging(groupSnapshot *crdv1beta2.VolumeGroupSnaps if groupSnapshot.Status != nil && groupSnapshot.Status.ReadyToUse != nil { ready = *groupSnapshot.Status.ReadyToUse } - return fmt.Sprintf("bound to: %q, Completed: %v", groupSnapshotContentName, ready) + return fmt.Sprintf("bound to: %q, completed: %v", groupSnapshotContentName, ready) } func IsVolumeSnapshotRefSet(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent) bool { @@ -612,7 +601,7 @@ func IsBoundVolumeSnapshotContentNameSet(snapshot *crdv1.VolumeSnapshot) bool { } func IsSnapshotReady(snapshot *crdv1.VolumeSnapshot) bool { - if snapshot.Status == nil || snapshot.Status.ReadyToUse == nil || *snapshot.Status.ReadyToUse == false { + if snapshot.Status == nil || snapshot.Status.ReadyToUse == nil || !*snapshot.Status.ReadyToUse { return false } return true @@ -659,13 +648,13 @@ func IsGroupSnapshotCreated(groupSnapshot *crdv1beta2.VolumeGroupSnapshot) bool return groupSnapshot.Status != nil && groupSnapshot.Status.CreationTime != nil } -// GetDynamicSnapshotContentNameFoGrouprSnapshot returns a unique content name for the +// GetDynamicSnapshotContentNameForGroupSnapshot returns a unique content name for the // passed in VolumeGroupSnapshot to dynamically provision a group snapshot. func GetDynamicSnapshotContentNameForGroupSnapshot(groupSnapshot *crdv1beta2.VolumeGroupSnapshot) string { return "groupsnapcontent-" + string(groupSnapshot.UID) } -// ShouldEnqueueContentChange indicated whether or not a change to a VolumeSnapshotContent object +// ShouldEnqueueContentChange indicates whether or not a change to a VolumeSnapshotContent object // is a change that should be enqueued for sync // // The following changes are sanitized (and thus, not considered for determining whether to sync) diff --git a/pkg/webhook/convert.go b/pkg/webhook/convert.go index 6e8a08316..0248288d2 100644 --- a/pkg/webhook/convert.go +++ b/pkg/webhook/convert.go @@ -135,7 +135,7 @@ func convertVolumeGroupSnapshotContentFromV1beta2ToV1beta1(obj *unstructured.Uns // Step 2: convert volumeSnapshotInfoList to volumeSnapshotHandlePairList for i, entry := range volumeSnapshotInfoList { - if mapEntry, ok := entry.(map[string]interface{}); ok { + if mapEntry, ok := entry.(map[string]any); ok { delete(mapEntry, "creationTime") delete(mapEntry, "readyToUse") delete(mapEntry, "restoreSize") diff --git a/pkg/webhook/framework.go b/pkg/webhook/framework.go index 36b7e1df5..181d2b378 100644 --- a/pkg/webhook/framework.go +++ b/pkg/webhook/framework.go @@ -42,7 +42,7 @@ import ( // template that can be used for any CR conversion given this function. type convertFunc func(Object *unstructured.Unstructured, version string) (*unstructured.Unstructured, metav1.Status) -func statusErrorWithMessage(msg string, params ...interface{}) metav1.Status { +func statusErrorWithMessage(msg string, params ...any) metav1.Status { return metav1.Status{ Message: fmt.Sprintf(msg, params...), Status: metav1.StatusFailure, diff --git a/pkg/webhook/webhook_test.go b/pkg/webhook/webhook_test.go index 2165f4246..5389726ff 100644 --- a/pkg/webhook/webhook_test.go +++ b/pkg/webhook/webhook_test.go @@ -17,7 +17,6 @@ limitations under the License. package webhook import ( - "context" "crypto/rand" "crypto/rsa" "crypto/tls" @@ -55,8 +54,7 @@ func TestWebhookCertReload(t *testing.T) { } // Start test server - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() cw, err := NewCertWatcher(certFile, keyFile) if err != nil { t.Errorf("failed to initialize new cert watcher: %v", err) @@ -97,7 +95,7 @@ func TestWebhookCertReload(t *testing.T) { } // TC: Certificate should consistently change with a file change - for i := 0; i < 5; i++ { + for range 5 { // Generate new key/cert err = generateTestCertKeyPair(t, certFile, keyFile) if err != nil { @@ -134,7 +132,7 @@ func generateTestCertKeyPair(t *testing.T, certPath, keyPath string) error { return fmt.Errorf("Failed to generate serial number: %v", err) } - var priv interface{} + var priv any priv, err = rsa.GenerateKey(rand.Reader, 4096) if err != nil { return fmt.Errorf("Failed to generate key: %v", err) diff --git a/release-tools/verify-go-version.sh b/release-tools/verify-go-version.sh index c235e74fe..89f3df4a6 100755 --- a/release-tools/verify-go-version.sh +++ b/release-tools/verify-go-version.sh @@ -39,7 +39,7 @@ if [ "$majorminor" != "$expected" ]; then ====================================================== WARNING - This projects is tested with Go v$expected. + This project is tested with Go v$expected. Your current Go version is v$majorminor. This may or may not be close enough.