Fix flakes in portforward test.

Attempt to fix flaky port forward test using "netstat" in the container
to check the a process is listening on the port before attempting to
connect.

Also, re-enable the test in a seperate job, but w/ a soft fail. This
will be removed later in favor of adding port-forward to integration
tests to remove the high overhead of starting a new job (scheduling,
compiling runsc, downloading images, etc).

PiperOrigin-RevId: 526135859
This commit is contained in:
Zach Koopmans
2023-04-21 14:28:31 -07:00
committed by gVisor bot
parent 79b38029d7
commit 2e45ce14a4
4 changed files with 49 additions and 28 deletions
+9 -2
View File
@@ -238,7 +238,6 @@ steps:
<<: *kvm_agents
cgroup: "v2"
arch: "amd64"
# All system call tests.
- <<: *common
label: ":toolbox: System call tests (AMD64)"
@@ -271,7 +270,7 @@ steps:
# See above: not truly a source test.
<<: *source_test
label: ":docker: Docker tests (cgroupv2)"
command: make portforward-tests docker-tests
command: make docker-tests
agents:
<<: *ubuntu_agents
arch: "amd64"
@@ -284,6 +283,14 @@ steps:
<<: *platform_specific_agents
<<: *ubuntu_agents
arch: "amd64"
- <<: *common
<<: *docker
label: ":one-does-not-simply: Port-Forward tests"
command: make portforward-tests
agents:
<<: *ubuntu_agents
arch: "amd64"
soft_fail: true
- <<: *common
<<: *docker
label: ":safety_pin: Host network tests"
+2 -2
View File
@@ -264,9 +264,9 @@ simple-tests: unit-tests # Compatibility target.
portforward-tests: load-basic_redis load-basic_nginx $(RUNTIME_BIN)
@$(call install_runtime,$(RUNTIME),--network=sandbox)
@$(call sudo,test/root:portforward_test,--runtime=$(RUNTIME) -test.v)
@$(call sudo,test/root:portforward_test,--runtime=$(RUNTIME) -test.v $(ARGS))
@$(call install_runtime,$(RUNTIME),--network=host)
@$(call sudo,test/root:portforward_test,--runtime=$(RUNTIME) -test.v)
@$(call sudo,test/root:portforward_test,--runtime=$(RUNTIME) -test.v $(ARGS))
.PHONY: portforward-test
# Standard integration targets.
+2
View File
@@ -1 +1,3 @@
FROM redis:5.0.4
RUN apt-get update && apt-get install -y net-tools
+36 -24
View File
@@ -54,6 +54,10 @@ func TestPortForwardLocalMode(t *testing.T) {
t.Fatalf("failed to create redis server: %v", err)
}
if err := waitUntilServerIsUp(ctx, server, redisPort); err != nil {
t.Fatalf("failed to wait for redis server to be up: %v", err)
}
localPort, err := getUnusedPort()
if err != nil {
t.Fatalf("failed to pick unused port: %v", err)
@@ -120,30 +124,8 @@ func TestPortForwardStreamMode(t *testing.T) {
t.Fatalf("failed to create nginx server: %v", err)
}
// This is a bit crude, but we need to make sure the server is up without exposing a port to the
// host. When the server container boots, the nginx process should run first. If we run nginx
// again, it will fail to bind to port 80. Run exec calls until we get that failure.
serverUpChan := make(chan struct{}, 1)
var upOut string
var upErr error
reg := regexp.MustCompile(`0\.0\.0\.0:80[\s]*0\.0\.0\.0:\*[\s]*LISTEN`)
go func() {
for {
time.Sleep(time.Millisecond * 500)
upOut, upErr = server.Exec(ctx, dockerutil.ExecOpts{}, []string{"netstat", "-l"}...)
if reg.MatchString(upOut) {
serverUpChan <- struct{}{}
return
}
}
}()
// If the server isn't up after 10 seconds, there is probably something wrong.
select {
case <-serverUpChan:
break
case <-time.After(time.Second * 30):
t.Fatalf("could not verify server is up: err: %v out: %s", upErr, upOut)
if err := waitUntilServerIsUp(ctx, server, nginxPort); err != nil {
t.Fatalf("failed to wait for nginx server to be up: %v", err)
}
socket, err := net.Listen("unix", sockAddr)
@@ -192,6 +174,36 @@ func getUnusedPort() (int, error) {
return l.Addr().(*net.TCPAddr).Port, nil
}
func waitUntilServerIsUp(ctx context.Context, server *dockerutil.Container, port int) error {
// This is a bit crude, but we need to make sure the server is up without exposing a port to the
// host. When the server container boots, the nginx process should run first. If we run nginx
// again, it will fail to bind to port 80. Run exec calls until we get that failure.
serverUpChan := make(chan struct{})
var upOut string
var upErr error
reg := regexp.MustCompile(fmt.Sprintf(`0\.0\.0\.0:%d[\s]*0\.0\.0\.0:\*[\s]*LISTEN`, port))
go func() {
for {
time.Sleep(time.Millisecond * 500)
upOut, upErr = server.Exec(ctx, dockerutil.ExecOpts{}, []string{"netstat", "-l"}...)
if reg.MatchString(upOut) {
close(serverUpChan)
return
}
}
}()
// If the server isn't up after 30 seconds, there is probably something wrong.
select {
case <-serverUpChan:
break
case <-time.After(time.Second * 30):
return fmt.Errorf("could not verify server is up: err: %v out: %s", upErr, upOut)
}
return nil
}
type portForwardProcess struct {
cmd *exec.Cmd
buf bytes.Buffer