diff --git a/.golangci.yaml b/.golangci.yaml index c0a8028a7f..6e97f103c6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -6,7 +6,6 @@ run: - injection/clients output: - uniq-by-line: true sort-results: true sort-order: - linter @@ -15,6 +14,7 @@ output: issues: + uniq-by-line: true max-issues-per-linter: 0 max-same-issues: 0 exclude-rules: @@ -103,9 +103,6 @@ linters: # problems with the error wrapping scheme introduced in Go 1.13. - errorlint - # Checks for pointers to enclosing loop variables. - - exportloopref - # Detects nested contexts in loops. - fatcontext diff --git a/apis/testing/roundtrip/roundtrip.go b/apis/testing/roundtrip/roundtrip.go index 54493b02e2..271a5b1098 100644 --- a/apis/testing/roundtrip/roundtrip.go +++ b/apis/testing/roundtrip/roundtrip.go @@ -135,7 +135,7 @@ func ExternalTypesViaHub(t *testing.T, scheme, hubs *runtime.Scheme, fuzzerFuncs continue } - if reflect.PtrTo(objType).AssignableTo(metaV1ListType) { + if reflect.PointerTo(objType).AssignableTo(metaV1ListType) { continue } diff --git a/controller/controller.go b/controller/controller.go index 152d837d6d..bb5ab347a1 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -228,7 +228,7 @@ type ControllerOptions struct { WorkQueueName string Logger *zap.SugaredLogger Reporter StatsReporter - RateLimiter workqueue.RateLimiter + RateLimiter workqueue.TypedRateLimiter[any] Concurrency int } @@ -236,7 +236,7 @@ type ControllerOptions struct { // provided Reconciler as it is enqueued. func NewContext(ctx context.Context, r Reconciler, options ControllerOptions) *Impl { if options.RateLimiter == nil { - options.RateLimiter = workqueue.DefaultControllerRateLimiter() + options.RateLimiter = workqueue.DefaultTypedControllerRateLimiter[any]() } if options.Reporter == nil { options.Reporter = MustNewStatsReporter(options.WorkQueueName, options.Logger) @@ -263,7 +263,7 @@ func NewContext(ctx context.Context, r Reconciler, options ControllerOptions) *I } // WorkQueue permits direct access to the work queue. -func (c *Impl) WorkQueue() workqueue.RateLimitingInterface { +func (c *Impl) WorkQueue() workqueue.TypedRateLimitingInterface[any] { return c.workQueue } diff --git a/controller/controller_test.go b/controller/controller_test.go index 261be297a2..e4b7f744f6 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -411,7 +411,7 @@ func (t testRateLimiter) When(interface{}) time.Duration { return t.delay } func (t testRateLimiter) Forget(interface{}) {} func (t testRateLimiter) NumRequeues(interface{}) int { return 0 } -var _ workqueue.RateLimiter = (*testRateLimiter)(nil) +var _ workqueue.TypedRateLimiter[any] = (*testRateLimiter)(nil) func TestEnqueue(t *testing.T) { tests := []struct { @@ -715,7 +715,7 @@ func TestEnqueue(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - var rl workqueue.RateLimiter = testRateLimiter{t, 100 * time.Millisecond} + var rl workqueue.TypedRateLimiter[any] = testRateLimiter{t, 100 * time.Millisecond} impl := NewContext(context.TODO(), &nopReconciler{}, ControllerOptions{WorkQueueName: "Testing", Logger: TestLogger(t), RateLimiter: rl}) test.work(impl) @@ -741,7 +741,7 @@ const ( queueCheckTimeout = shortDelay + 500*time.Millisecond ) -func pollQ(q workqueue.RateLimitingInterface, sig chan int) func(context.Context) (bool, error) { +func pollQ(q workqueue.TypedRateLimitingInterface[any], sig chan int) func(context.Context) (bool, error) { return func(context.Context) (bool, error) { if ql := q.Len(); ql > 0 { sig <- ql @@ -1356,7 +1356,7 @@ func TestStartAndShutdownWithRequeuingWork(t *testing.T) { } } -func drainWorkQueue(wq workqueue.RateLimitingInterface) (hasQueue []types.NamespacedName) { +func drainWorkQueue(wq workqueue.TypedRateLimitingInterface[any]) (hasQueue []types.NamespacedName) { for { key, shutdown := wq.Get() if key == nil && shutdown { diff --git a/controller/two_lane_queue.go b/controller/two_lane_queue.go index d3656285b8..86299c2975 100644 --- a/controller/two_lane_queue.go +++ b/controller/two_lane_queue.go @@ -23,12 +23,12 @@ import "k8s.io/client-go/util/workqueue" // -- slow queue (slowLane queue), whose contents are processed if fast queue has no items. // All the default methods operate on the fast queue, unless noted otherwise. type twoLaneQueue struct { - workqueue.RateLimitingInterface - slowLane workqueue.RateLimitingInterface + workqueue.TypedRateLimitingInterface[any] + slowLane workqueue.TypedRateLimitingInterface[any] // consumerQueue is necessary to ensure that we're not reconciling // the same object at the exact same time (e.g. if it had been enqueued // in both fast and slow and is the only object there). - consumerQueue workqueue.Interface + consumerQueue workqueue.TypedInterface[any] name string @@ -37,9 +37,9 @@ type twoLaneQueue struct { } // Creates a new twoLaneQueue. -func newTwoLaneWorkQueue(name string, rl workqueue.RateLimiter) *twoLaneQueue { +func newTwoLaneWorkQueue(name string, rl workqueue.TypedRateLimiter[any]) *twoLaneQueue { tlq := &twoLaneQueue{ - RateLimitingInterface: workqueue.NewNamedRateLimitingQueue( + TypedRateLimitingInterface: workqueue.NewNamedRateLimitingQueue( rl, name+"-fast", ), @@ -55,12 +55,12 @@ func newTwoLaneWorkQueue(name string, rl workqueue.RateLimiter) *twoLaneQueue { // Run consumer thread. go tlq.runConsumer() // Run producer threads. - go process(tlq.RateLimitingInterface, tlq.fastChan) + go process(tlq.TypedRateLimitingInterface, tlq.fastChan) go process(tlq.slowLane, tlq.slowChan) return tlq } -func process(q workqueue.Interface, ch chan interface{}) { +func process(q workqueue.TypedInterface[any], ch chan interface{}) { // Sender closes the channel defer close(ch) for { @@ -125,7 +125,7 @@ func (tlq *twoLaneQueue) runConsumer() { // Shutdown implements workqueue.Interface. // Shutdown shuts down both queues. func (tlq *twoLaneQueue) ShutDown() { - tlq.RateLimitingInterface.ShutDown() + tlq.TypedRateLimitingInterface.ShutDown() tlq.slowLane.ShutDown() } @@ -147,10 +147,10 @@ func (tlq *twoLaneQueue) Get() (interface{}, bool) { // Len returns the sum of lengths. // NB: actual _number_ of unique object might be less than this sum. func (tlq *twoLaneQueue) Len() int { - return tlq.RateLimitingInterface.Len() + tlq.slowLane.Len() + tlq.consumerQueue.Len() + return tlq.TypedRateLimitingInterface.Len() + tlq.slowLane.Len() + tlq.consumerQueue.Len() } // SlowLane gives direct access to the slow queue. -func (tlq *twoLaneQueue) SlowLane() workqueue.RateLimitingInterface { +func (tlq *twoLaneQueue) SlowLane() workqueue.TypedRateLimitingInterface[any] { return tlq.slowLane } diff --git a/controller/two_lane_queue_test.go b/controller/two_lane_queue_test.go index 46a18ce39e..d75b63fd8b 100644 --- a/controller/two_lane_queue_test.go +++ b/controller/two_lane_queue_test.go @@ -45,7 +45,7 @@ func (r *chanRateLimiter) NumRequeues(item interface{}) int { return 0 } -var _ workqueue.RateLimiter = &chanRateLimiter{} +var _ workqueue.TypedRateLimiter[any] = &chanRateLimiter{} func TestRateLimit(t *testing.T) { // Verifies that we properly pass the rate limiter to the queue. @@ -87,7 +87,7 @@ func TestRateLimit(t *testing.T) { } func TestSlowQueue(t *testing.T) { - q := newTwoLaneWorkQueue("live-in-the-fast-lane", workqueue.DefaultControllerRateLimiter()) + q := newTwoLaneWorkQueue("live-in-the-fast-lane", workqueue.DefaultTypedControllerRateLimiter[any]()) q.SlowLane().Add("1") // Queue has async moving parts so if we check at the wrong moment, this might still be 0. if wait.PollUntilContextTimeout(context.Background(), 10*time.Millisecond, 250*time.Millisecond, true, func(ctx context.Context) (bool, error) { @@ -115,7 +115,7 @@ func TestSlowQueue(t *testing.T) { func TestDoubleKey(t *testing.T) { // Verifies that we don't get double concurrent processing of the same key. - q := newTwoLaneWorkQueue("live-in-the-fast-lane", workqueue.DefaultControllerRateLimiter()) + q := newTwoLaneWorkQueue("live-in-the-fast-lane", workqueue.DefaultTypedControllerRateLimiter[any]()) q.Add("1") t.Cleanup(q.ShutDown) @@ -159,7 +159,7 @@ func TestDoubleKey(t *testing.T) { func TestOrder(t *testing.T) { // Verifies that we read from the fast queue first. - q := newTwoLaneWorkQueue("live-in-the-fast-lane", workqueue.DefaultControllerRateLimiter()) + q := newTwoLaneWorkQueue("live-in-the-fast-lane", workqueue.DefaultTypedControllerRateLimiter[any]()) stop := make(chan struct{}) t.Cleanup(func() { close(stop) diff --git a/hash/hash.go b/hash/hash.go index ae2969acd2..e51b999e95 100644 --- a/hash/hash.go +++ b/hash/hash.go @@ -35,7 +35,7 @@ const ( // universe represents the possible range of angles [0, universe). // We want to have universe divide total range evenly to reduce bias. - universe = (1 << 11) + universe uint64 = (1 << 11) ) // computeAngle returns a uint64 number which represents @@ -51,13 +51,13 @@ func computeHash(n []byte, h hash.Hash64) uint64 { type hashData struct { // The set of all hashes for fast lookup and to name mapping - nameLookup map[int]string + nameLookup map[uint64]string // Sorted set of hashes for selection algorithm. - hashPool []int + hashPool []uint64 // start angle - start int + start uint64 // step angle - step int + step uint64 } func (hd *hashData) fromIndexSet(s sets.Set[int]) sets.Set[string] { @@ -85,13 +85,13 @@ func buildHashes(in sets.Set[string], target string) *hashData { buf.WriteString(startSalt) hasher := fnv.New64a() hd := &hashData{ - nameLookup: make(map[int]string, len(from)), - hashPool: make([]int, len(from)), - start: int(computeHash(buf.Bytes(), hasher) % universe), + nameLookup: make(map[uint64]string, len(from)), + hashPool: make([]uint64, len(from)), + start: computeHash(buf.Bytes(), hasher) % universe, } buf.Truncate(len(target)) // Discard the angle salt. buf.WriteString(stepSalt) - hd.step = int(computeHash(buf.Bytes(), hasher) % universe) + hd.step = computeHash(buf.Bytes(), hasher) % universe for i, f := range from { buf.Reset() // This retains the storage. @@ -99,7 +99,7 @@ func buildHashes(in sets.Set[string], target string) *hashData { buf.WriteString(f) buf.WriteString(target) h := computeHash(buf.Bytes(), hasher) - hs := int(h % universe) + hs := h % universe // Two values slotted to the same bucket. // On average should happen with 1/universe probability. _, ok := hd.nameLookup[hs] @@ -107,7 +107,7 @@ func buildHashes(in sets.Set[string], target string) *hashData { // Feed the hash as salt. buf.WriteString(strconv.FormatUint(h, 16 /*append hex strings for shortness*/)) h = computeHash(buf.Bytes(), hasher) - hs = int(h % universe) + hs = h % universe _, ok = hd.nameLookup[hs] } diff --git a/hash/hash_test.go b/hash/hash_test.go index a1706d0c2c..6b41c3fe73 100644 --- a/hash/hash_test.go +++ b/hash/hash_test.go @@ -185,7 +185,7 @@ func BenchmarkSelection(b *testing.B) { b.Run(fmt.Sprintf("pool-%d-subset-%d", v, ss), func(b *testing.B) { target := uuid.NewString() in := sets.New[string](from[:v]...) - for i := 0; i < b.N; i++ { + for range b.N { ChooseSubset(in, 10, target) } }) diff --git a/kmeta/names_test.go b/kmeta/names_test.go index 0df0923019..6db08b93a7 100644 --- a/kmeta/names_test.go +++ b/kmeta/names_test.go @@ -17,7 +17,6 @@ limitations under the license. package kmeta import ( - "fmt" "strings" "testing" @@ -70,7 +69,7 @@ func TestChildName(t *testing.T) { t.Run(test.parent+"-"+test.suffix, func(t *testing.T) { got, want := ChildName(test.parent, test.suffix), test.want if errs := validation.IsDNS1123Subdomain(got); len(errs) != 0 { - t.Errorf(fmt.Sprintf("Invalid DNS1123 Subdomain %63s\n\n Errors: %v", got, errs)) + t.Errorf("Invalid DNS1123 Subdomain %63s\n\n Errors: %v", got, errs) } if got != want { t.Errorf("%s-%s: got: %63s want: %63s\ndiff:%s", test.parent, test.suffix, got, want, cmp.Diff(want, got)) diff --git a/metrics/config.go b/metrics/config.go index 9ed17ef678..6cea1b33a4 100644 --- a/metrics/config.go +++ b/metrics/config.go @@ -232,7 +232,7 @@ func prometheusPort() (int, error) { return defaultPrometheusPort, nil } - pp, err := strconv.ParseUint(ppStr, 10, 16) + pp, err := strconv.ParseInt(ppStr, 10, 16) if err != nil { return -1, fmt.Errorf("the environment variable %q could not be parsed as a port number: %w", prometheusPortEnvName, err) diff --git a/metrics/memstats.go b/metrics/memstats.go index d96a0f4bc5..ca090bba1f 100644 --- a/metrics/memstats.go +++ b/metrics/memstats.go @@ -19,6 +19,7 @@ package metrics import ( "context" "log" + "math" "runtime" "time" @@ -379,76 +380,76 @@ func (msp *MemStatsProvider) Start(ctx context.Context, period time.Duration) { ms := runtime.MemStats{} runtime.ReadMemStats(&ms) if msp.Alloc != nil { - Record(ctx, msp.Alloc.M(int64(ms.Alloc))) + Record(ctx, msp.Alloc.M(safeint64(ms.Alloc))) } if msp.TotalAlloc != nil { - Record(ctx, msp.TotalAlloc.M(int64(ms.TotalAlloc))) + Record(ctx, msp.TotalAlloc.M(safeint64(ms.TotalAlloc))) } if msp.Sys != nil { - Record(ctx, msp.Sys.M(int64(ms.Sys))) + Record(ctx, msp.Sys.M(safeint64(ms.Sys))) } if msp.Lookups != nil { - Record(ctx, msp.Lookups.M(int64(ms.Lookups))) + Record(ctx, msp.Lookups.M(safeint64(ms.Lookups))) } if msp.Mallocs != nil { - Record(ctx, msp.Mallocs.M(int64(ms.Mallocs))) + Record(ctx, msp.Mallocs.M(safeint64(ms.Mallocs))) } if msp.Frees != nil { - Record(ctx, msp.Frees.M(int64(ms.Frees))) + Record(ctx, msp.Frees.M(safeint64(ms.Frees))) } if msp.HeapAlloc != nil { - Record(ctx, msp.HeapAlloc.M(int64(ms.HeapAlloc))) + Record(ctx, msp.HeapAlloc.M(safeint64(ms.HeapAlloc))) } if msp.HeapSys != nil { - Record(ctx, msp.HeapSys.M(int64(ms.HeapSys))) + Record(ctx, msp.HeapSys.M(safeint64(ms.HeapSys))) } if msp.HeapIdle != nil { - Record(ctx, msp.HeapIdle.M(int64(ms.HeapIdle))) + Record(ctx, msp.HeapIdle.M(safeint64(ms.HeapIdle))) } if msp.HeapInuse != nil { - Record(ctx, msp.HeapInuse.M(int64(ms.HeapInuse))) + Record(ctx, msp.HeapInuse.M(safeint64(ms.HeapInuse))) } if msp.HeapReleased != nil { - Record(ctx, msp.HeapReleased.M(int64(ms.HeapReleased))) + Record(ctx, msp.HeapReleased.M(safeint64(ms.HeapReleased))) } if msp.HeapObjects != nil { - Record(ctx, msp.HeapObjects.M(int64(ms.HeapObjects))) + Record(ctx, msp.HeapObjects.M(safeint64(ms.HeapObjects))) } if msp.StackInuse != nil { - Record(ctx, msp.StackInuse.M(int64(ms.StackInuse))) + Record(ctx, msp.StackInuse.M(safeint64(ms.StackInuse))) } if msp.StackSys != nil { - Record(ctx, msp.StackSys.M(int64(ms.StackSys))) + Record(ctx, msp.StackSys.M(safeint64(ms.StackSys))) } if msp.MSpanInuse != nil { - Record(ctx, msp.MSpanInuse.M(int64(ms.MSpanInuse))) + Record(ctx, msp.MSpanInuse.M(safeint64(ms.MSpanInuse))) } if msp.MSpanSys != nil { - Record(ctx, msp.MSpanSys.M(int64(ms.MSpanSys))) + Record(ctx, msp.MSpanSys.M(safeint64(ms.MSpanSys))) } if msp.MCacheInuse != nil { - Record(ctx, msp.MCacheInuse.M(int64(ms.MCacheInuse))) + Record(ctx, msp.MCacheInuse.M(safeint64(ms.MCacheInuse))) } if msp.MCacheSys != nil { - Record(ctx, msp.MCacheSys.M(int64(ms.MCacheSys))) + Record(ctx, msp.MCacheSys.M(safeint64(ms.MCacheSys))) } if msp.BuckHashSys != nil { - Record(ctx, msp.BuckHashSys.M(int64(ms.BuckHashSys))) + Record(ctx, msp.BuckHashSys.M(safeint64(ms.BuckHashSys))) } if msp.GCSys != nil { - Record(ctx, msp.GCSys.M(int64(ms.GCSys))) + Record(ctx, msp.GCSys.M(safeint64(ms.GCSys))) } if msp.OtherSys != nil { - Record(ctx, msp.OtherSys.M(int64(ms.OtherSys))) + Record(ctx, msp.OtherSys.M(safeint64(ms.OtherSys))) } if msp.NextGC != nil { - Record(ctx, msp.NextGC.M(int64(ms.NextGC))) + Record(ctx, msp.NextGC.M(safeint64(ms.NextGC))) } if msp.LastGC != nil { - Record(ctx, msp.LastGC.M(int64(ms.LastGC))) + Record(ctx, msp.LastGC.M(safeint64(ms.LastGC))) } if msp.PauseTotalNs != nil { - Record(ctx, msp.PauseTotalNs.M(int64(ms.PauseTotalNs))) + Record(ctx, msp.PauseTotalNs.M(safeint64(ms.PauseTotalNs))) } if msp.NumGC != nil { Record(ctx, msp.NumGC.M(int64(ms.NumGC))) @@ -549,3 +550,11 @@ func (msp *MemStatsProvider) DefaultViews() (views []*view.View) { } return } + +func safeint64(val uint64) int64 { + if val > math.MaxInt64 { + return math.MaxInt64 + } + + return int64(val) +} diff --git a/metrics/record_test.go b/metrics/record_test.go index a019814105..6bb55d2666 100644 --- a/metrics/record_test.go +++ b/metrics/record_test.go @@ -162,7 +162,7 @@ func BenchmarkMetricsRecording(b *testing.B) { b.Error("Failed to create tags") } b.Run("sequential", func(b *testing.B) { - for j := 0; j < b.N; j++ { + for range b.N { ctx, err := getTagCtx() if err != nil { b.Error("Failed to get context") @@ -182,7 +182,7 @@ func BenchmarkMetricsRecording(b *testing.B) { }) }) b.Run("sequential-batch", func(b *testing.B) { - for j := 0; j < b.N; j++ { + for range b.N { ctx, err := getTagCtx() if err != nil { b.Error("Failed to get context") diff --git a/metrics/resource_view_test.go b/metrics/resource_view_test.go index 4475d3de1f..bccb51dc5b 100644 --- a/metrics/resource_view_test.go +++ b/metrics/resource_view_test.go @@ -286,7 +286,7 @@ func BenchmarkResourceToKey(b *testing.B) { r := &resource.Resource{Type: "foobar", Labels: labels} b.Run(fmt.Sprintf("%d-labels", count), func(b *testing.B) { - for i := 0; i < b.N; i++ { + for range b.N { resourceToKey(r) } }) diff --git a/test/imports/banned_deps_test.go b/test/imports/banned_deps_test.go index b48c8065df..c0211ced8e 100644 --- a/test/imports/banned_deps_test.go +++ b/test/imports/banned_deps_test.go @@ -74,6 +74,6 @@ func TestBannedImports(t *testing.T) { return nil }) if err != nil { - t.Errorf(err.Error()) + t.Error(err.Error()) } } diff --git a/tracing/http_test.go b/tracing/http_test.go index 0b31005acc..10d1c79870 100644 --- a/tracing/http_test.go +++ b/tracing/http_test.go @@ -212,7 +212,7 @@ func BenchmarkSpanMiddleware(b *testing.B) { req.Header["X-B3-Spanid"] = []string{"b3bd5e1c4318c78a"} b.Run("sequential", func(b *testing.B) { - for j := 0; j < b.N; j++ { + for range b.N { middleware.ServeHTTP(bw, req) } }) diff --git a/webhook/admission_integration_test.go b/webhook/admission_integration_test.go index 3a3096de7c..6ed1e306dc 100644 --- a/webhook/admission_integration_test.go +++ b/webhook/admission_integration_test.go @@ -351,7 +351,7 @@ func TestAdmissionInvalidResponseForResource(t *testing.T) { expectedError := "everything is fine." ac := &fixedAdmissionController{ path: "/booger", - response: MakeErrorStatus(expectedError), + response: MakeErrorStatus(expectedError), //nolint } wh, serverURL, ctx, cancel, err := testSetup(t, ac) if err != nil { diff --git a/webhook/testing/factory.go b/webhook/testing/factory.go index b35d955da4..d34938578d 100644 --- a/webhook/testing/factory.go +++ b/webhook/testing/factory.go @@ -96,6 +96,7 @@ func MakeFactory(ctor Ctor) rtesting.Factory { // Set up our Controller from the fakes. c := ctor(ctx, &ls, configmap.NewStaticWatcher()) // Update the context with the stuff we decorated it with. + //nolint:fatcontext // Drop when https://github.com/Crocmagnon/fatcontext/issues/34 is fixed r.Ctx = ctx // If the reconcilers is leader aware, then promote it.