testcontainers-go
testcontainers-go copied to clipboard
setup ExposeHostPorts forwards on container start
What does this PR do?
Changes the lifecycle hook for the ExposedHostPorts forwarding to happen on PreCreates of the testcontainer instead of PostReadies. Additionally updates the port forwarding tests to ensure the host ports are accessible on startup and that there's no issues even if the host isn't listening until PostCreates.
Why is it important?
Previously ExposedHostPorts would start an SSHD container prior to starting the testcontainer and inject a PostReadies lifecycle hook into the testcontainer in order to set up remote port forwarding from the host to the SSHD container so the testcontainer can talk to the host via the SSHD container
This would be an issue if the testcontainer depends on accessing the host port on startup ( e.g., a proxy server ) as the forwarding for the host access isn't set up until all the WiatFor strategies on the testcontainer have completed.
Related issues
- Fixes #2811
How to test this PR
go test port_forwarding_test.go
Additionally, I've provided a minimal example of my use case where I ran into the issue trying to test my Caddy configuration as an API gateway using testcontainers.
package caddy_test
import (
"bytes"
"context"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)
const caddyFileContent = `
listen :80
reverse_proxy /api/* {
to {$API_SERVER}
health_uri /health
health_status 200
health_interval 10s
}
`
func TestCaddyfile(t *testing.T) {
ctx := context.Background()
apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}))
apiServerPort := apiServer.Listener.Addr().(*net.TCPAddr).Port
caddyContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "caddy:2.8.4",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForLog("server running"),
Env: map[string]string{
"API_SERVER": fmt.Sprintf("http://%s:%d", testcontainers.HostInternal, apiServerPort),
},
Files: []testcontainers.ContainerFile{
{
Reader: bytes.NewReader([]byte(caddyFileContent)),
ContainerFilePath: "/etc/caddy/Caddyfile",
},
},
HostAccessPorts: []int{apiServerPort},
},
Started: true,
})
require.NoError(t, err)
defer caddyContainer.Terminate(ctx)
caddyURL, err := caddyContainer.PortEndpoint(ctx, "80/tcp", "http")
require.NoError(t, err)
resp, err := http.Get(caddyURL + "/api/test")
require.NoError(t, err)
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, "Hello, World!", string(body))
lr, err := caddyContainer.Logs(ctx)
assert.NoError(t, err)
lb, err := io.ReadAll(lr)
assert.NoError(t, err)
fmt.Printf("== Caddy Logs ==\n%s================\n\n", string(lb))
}
Deploy Preview for testcontainers-go ready!
| Name | Link |
|---|---|
| Latest commit | ad3f69803db981288d4501e8de9fd258cb4690a4 |
| Latest deploy log | https://app.netlify.com/sites/testcontainers-go/deploys/67017de89ef93400086b7076 |
| Deploy Preview | https://deploy-preview-2815--testcontainers-go.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify site configuration.
Thanks for the PR, I've replied the issue, as it seems this is possible without using SSHD port forwarding, so wonder if that's the better way?
Thanks for the PR. As HostAccessPorts is part of the API, it is really expected that this work also at startup time, not just when doing Exec later on. I just lost half a day trying to figure out why this wasn't working and to end up here. Looking forward to see it merged.
Thanks for the PR. As HostAccessPorts is part of the API, it is really expected that this work also at startup time, not just when doing Exec later on. I just lost half a day trying to figure out why this wasn't working and to end up here. Looking forward to see it merged.
Thanks for the feedback, sounds like it should be clearly documented or fixed so it works too.
Hi @hathvi I'm reviewing this PR, and found there are conflicts that must be resolved. I wanted to do it myself locally, but as this PR was sent from your main branch, I cannot push my changes to it. Would you mind resolving them and pushing them again please?
I'd like to include this fix into the next release if possible.
Thanks
@hathvi I'm closing this one in favour of https://github.com/testcontainers/testcontainers-go/pull/3200. I've moved there the PR description and all your commits, for attribution. I'll also update the release notes to make you appear there as author of the original PR. Please read https://github.com/testcontainers/testcontainers-go/pull/2815#issuecomment-2821087290 about submitting PRs from the main branch 🙏
If you have any concern or question, let's follow-up in #3200