test/integration/framework: avoid race around grpclog.SetLoggerV2

grpclog.SetLoggerV is not thread-safe and may only be called before code starts
using GRPC. Calling RunCustomEtcd multiple times, for example in
k8s.io/kubernetes/test/integration/apiserver.TestWatchCacheUpdatedByEtcd,
causes a data race:

WARNING: DATA RACE
Read at 0x00000c8e8d20 by goroutine 135612:
  k8s.io/kubernetes/vendor/google.golang.org/grpc/grpclog.V()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/google.golang.org/grpc/grpclog/grpclog.go:41 +0x30
  k8s.io/kubernetes/vendor/google.golang.org/grpc/grpclog.(*componentData).V()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/google.golang.org/grpc/grpclog/component.go:103 +0x4e
  k8s.io/kubernetes/vendor/google.golang.org/grpc/internal/transport.(*loopyWriter).run.func1()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/google.golang.org/grpc/internal/transport/controlbuf.go:528 +0xf1
  runtime.deferreturn()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/.gimme/versions/go1.20.2.linux.amd64/src/runtime/panic.go:476 +0x32
  k8s.io/kubernetes/vendor/google.golang.org/grpc/internal/transport.newHTTP2Client.func6()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/google.golang.org/grpc/internal/transport/http2_client.go:442 +0x112

Previous write at 0x00000c8e8d20 by goroutine 140228:
  k8s.io/kubernetes/vendor/google.golang.org/grpc/grpclog.SetLoggerV2()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/vendor/google.golang.org/grpc/grpclog/loggerv2.go:76 +0xc6a
  k8s.io/kubernetes/test/integration/framework.RunCustomEtcd()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/test/integration/framework/etcd.go:153 +0xb89
  k8s.io/kubernetes/test/integration/apiserver.multiEtcdSetup()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/test/integration/apiserver/watchcache_test.go:40 +0xac
  k8s.io/kubernetes/test/integration/apiserver.TestWatchCacheUpdatedByEtcd()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/go/src/k8s.io/kubernetes/test/integration/apiserver/watchcache_test.go:88 +0x4a
  testing.tRunner()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/.gimme/versions/go1.20.2.linux.amd64/src/testing/testing.go:1576 +0x216
  testing.(*T).Run.func1()
      /home/prow/go/src/k8s.io/kubernetes/_output/local/.gimme/versions/go1.20.2.linux.amd64/src/testing/testing.go:1629 +0x47
This commit is contained in:
Patrick Ohly 2023-04-04 19:25:18 +02:00
parent d89d5ab268
commit 1dde8ef026

View File

@ -25,6 +25,7 @@ import (
"os"
"os/exec"
"strings"
"sync"
"syscall"
"testing"
"time"
@ -83,6 +84,8 @@ func startEtcd(output io.Writer) (func(), error) {
return stop, nil
}
var initGRPCOnce sync.Once
// RunCustomEtcd starts a custom etcd instance for test purposes.
func RunCustomEtcd(dataDir string, customFlags []string, output io.Writer) (url string, stopFn func(), err error) {
// TODO: Check for valid etcd version.
@ -150,7 +153,9 @@ func RunCustomEtcd(dataDir string, customFlags []string, output io.Writer) (url
// Quiet etcd logs for integration tests
// Comment out to get verbose logs if desired
grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, os.Stderr))
initGRPCOnce.Do(func() {
grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, os.Stderr))
})
if err := cmd.Start(); err != nil {
return "", nil, fmt.Errorf("failed to run etcd: %v", err)