From 26cad7b36a97246b0f16314c4a452d0a043e36e3 Mon Sep 17 00:00:00 2001 From: Cezar Sa Espinola Date: Wed, 31 Jan 2018 17:11:42 -0200 Subject: [PATCH] testing: fix race condition reading data from containers Example of a race caught by the race detector: ``` ================== WARNING: DATA RACE Write at 0x00c4201dea68 by goroutine 374: github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).stopContainer() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:726 +0x15a github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).(github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.stopContainer)-fm() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:169 +0x5f github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).handlerWrapper.func1() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:379 +0x70a net/http.HandlerFunc.ServeHTTP() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:1918 +0x51 github.com/tsuru/tsuru/vendor/github.com/gorilla/mux.(*Router).ServeHTTP() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/gorilla/mux/mux.go:133 +0x18a github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).ServeHTTP() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:340 +0x271 net/http.serverHandler.ServeHTTP() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:2619 +0xbc net/http.(*conn).serve() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:1801 +0x83b Previous read at 0x00c4201dea68 by goroutine 357: reflect.Value.Bool() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/reflect/value.go:248 +0x52 encoding/json.isEmptyValue() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:309 +0xd4 encoding/json.(*structEncoder).encode() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:626 +0x31f encoding/json.(*structEncoder).(encoding/json.encode)-fm() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:651 +0x7b encoding/json.(*structEncoder).encode() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:637 +0x2e2 encoding/json.(*structEncoder).(encoding/json.encode)-fm() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:651 +0x7b encoding/json.(*ptrEncoder).encode() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:778 +0x12a encoding/json.(*ptrEncoder).(encoding/json.encode)-fm() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:783 +0x7b encoding/json.(*encodeState).reflectValue() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:323 +0x93 encoding/json.(*encodeState).marshal() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/encode.go:296 +0xbc encoding/json.(*Encoder).Encode() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/encoding/json/stream.go:193 +0xda github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).inspectContainer() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:569 +0x289 github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).(github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.inspectContainer)-fm() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:165 +0x5f github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).handlerWrapper.func1() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:379 +0x70a net/http.HandlerFunc.ServeHTTP() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:1918 +0x51 github.com/tsuru/tsuru/vendor/github.com/gorilla/mux.(*Router).ServeHTTP() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/gorilla/mux/mux.go:133 +0x18a github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing.(*DockerServer).ServeHTTP() /home/travis/gopath/src/github.com/tsuru/tsuru/vendor/github.com/fsouza/go-dockerclient/testing/server.go:340 +0x271 net/http.serverHandler.ServeHTTP() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:2619 +0xbc net/http.(*conn).serve() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:1801 +0x83b Goroutine 374 (running) created at: net/http.(*Server).Serve() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:2720 +0x37c net/http.Serve() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:2323 +0xe2 Goroutine 357 (finished) created at: net/http.(*Server).Serve() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:2720 +0x37c net/http.Serve() /home/travis/.gimme/versions/go1.9.2.linux.amd64/src/net/http/server.go:2323 +0xe2 ================== ``` --- testing/server.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/testing/server.go b/testing/server.go index 57a9e657..75a2b318 100644 --- a/testing/server.go +++ b/testing/server.go @@ -547,10 +547,10 @@ func (s *DockerServer) renameContainer(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusNotFound) return } - copy := *container - copy.Name = r.URL.Query().Get("name") s.cMut.Lock() defer s.cMut.Unlock() + copy := *container + copy.Name = r.URL.Query().Get("name") if s.containers[index].ID == copy.ID { s.containers[index] = © } @@ -566,6 +566,8 @@ func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request) } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) + s.cMut.RLock() + defer s.cMut.RUnlock() json.NewEncoder(w).Encode(container) } @@ -820,16 +822,18 @@ func (s *DockerServer) waitContainer(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusNotFound) return } + var exitCode int for { time.Sleep(1e6) s.cMut.RLock() if !container.State.Running { + exitCode = container.State.ExitCode s.cMut.RUnlock() break } s.cMut.RUnlock() } - result := map[string]int{"StatusCode": container.State.ExitCode} + result := map[string]int{"StatusCode": exitCode} json.NewEncoder(w).Encode(result) } @@ -1153,7 +1157,9 @@ func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Reques } execID := s.generateID() + s.cMut.Lock() container.ExecIDs = append(container.ExecIDs, execID) + s.cMut.Unlock() exec := docker.ExecInspect{ ID: execID,