|
1 | 1 | package stores |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "context" |
5 | 6 | "fmt" |
| 7 | + "net" |
6 | 8 | "os" |
| 9 | + "strings" |
7 | 10 | "time" |
8 | 11 |
|
9 | 12 | "github.com/jackc/pgx/v5/pgxpool" |
@@ -31,7 +34,7 @@ func FromEnv(ctx context.Context) (Store, chan struct{}, error) { |
31 | 34 | } |
32 | 35 | return store, nil, nil |
33 | 36 |
|
34 | | - } else if _, hasDocker := os.LookupEnv("DOCKER_HOST"); hasDocker { |
| 37 | + } else if os.Getenv("ENV") == "local" || os.Getenv("ENV") == "test" { |
35 | 38 | pool, err := dockertest.NewPool("") |
36 | 39 | if err != nil { |
37 | 40 | return nil, nil, err |
@@ -66,7 +69,17 @@ func FromEnv(ctx context.Context) (Store, chan struct{}, error) { |
66 | 69 | return nil, nil, err |
67 | 70 | } |
68 | 71 | } |
69 | | - databaseUrl := fmt.Sprintf("postgres://test:test@%s/test?sslmode=disable", resource.GetHostPort("5432/tcp")) |
| 72 | + |
| 73 | + hostPort := resource.GetHostPort("5432/tcp") |
| 74 | + |
| 75 | + // If we are running in Docker, we need to replace localhost with host.docker.internal. |
| 76 | + // This allows us to connect to the postgres dockertest just started inside our container. |
| 77 | + // localhost will not work in this case as it refers to the container itself. |
| 78 | + if runningInDocker() { |
| 79 | + hostPort = strings.ReplaceAll(hostPort, "localhost", "host.docker.internal") |
| 80 | + } |
| 81 | + |
| 82 | + databaseUrl := fmt.Sprintf("postgres://test:test@%s/test?sslmode=disable", hostPort) |
70 | 83 |
|
71 | 84 | // This log message is used by the test suite to pass the database URL to the testproxy. |
72 | 85 | logger.Info("using database", zap.String("url", databaseUrl)) |
@@ -95,5 +108,21 @@ func FromEnv(ctx context.Context) (Store, chan struct{}, error) { |
95 | 108 | } |
96 | 109 | return store, flushed, nil |
97 | 110 | } |
98 | | - return nil, nil, fmt.Errorf("no database configured export DATABASE_URL or DOCKER_HOST to run locally") |
| 111 | + return nil, nil, fmt.Errorf("no database configured, set DATABASE_URL in production, or ENV=local to automatically start a temporary database") |
| 112 | +} |
| 113 | + |
| 114 | +// runningInDocker returns true if the code is running inside a Docker container. |
| 115 | +func runningInDocker() bool { |
| 116 | + if _, err := os.Stat("/.dockerenv"); err == nil { |
| 117 | + return true |
| 118 | + } |
| 119 | + |
| 120 | + if b, err := os.ReadFile("/proc/1/cgroup"); err == nil { |
| 121 | + return bytes.Contains(b, []byte("docker")) || |
| 122 | + bytes.Contains(b, []byte("kubepods")) || |
| 123 | + bytes.Contains(b, []byte("containerd")) |
| 124 | + } |
| 125 | + |
| 126 | + _, err := net.LookupHost("host.docker.internal") |
| 127 | + return err == nil |
99 | 128 | } |
0 commit comments