1919package pgtest
2020
2121import (
22+ "bufio"
2223 "fmt"
24+ "os"
25+ "regexp"
26+ "time"
2327
2428 "github.com/golang-migrate/migrate"
2529 "github.com/golang-migrate/migrate/database/postgres"
@@ -33,6 +37,27 @@ import (
3337 "px.dev/pixie/src/shared/services/pg"
3438)
3539
40+ // selfContainerID returns the current Docker container ID by parsing
41+ // /proc/self/mountinfo. Docker bind-mounts /etc/hostname from
42+ // /var/lib/docker/containers/<id>/hostname, exposing the container ID.
43+ // Returns empty string if not running inside a Docker container.
44+ func selfContainerID () string {
45+ f , err := os .Open ("/proc/self/mountinfo" )
46+ if err != nil {
47+ return ""
48+ }
49+ defer f .Close ()
50+
51+ re := regexp .MustCompile (`/containers/([a-f0-9]{64})/hostname` )
52+ scanner := bufio .NewScanner (f )
53+ for scanner .Scan () {
54+ if m := re .FindStringSubmatch (scanner .Text ()); m != nil {
55+ return m [1 ]
56+ }
57+ }
58+ return ""
59+ }
60+
3661// SetupTestDB sets up a test database instance and applies migrations.
3762func SetupTestDB (schemaSource * bindata.AssetSource ) (* sqlx.DB , func (), error ) {
3863 var db * sqlx.DB
@@ -69,18 +94,58 @@ func SetupTestDB(schemaSource *bindata.AssetSource) (*sqlx.DB, func(), error) {
6994 if err != nil {
7095 return nil , nil , fmt .Errorf ("Failed to run docker pool: %w" , err )
7196 }
72- // Set a 5 minute expiration on resources.
73- err = resource .Expire (300 )
97+ // Set a 15 minute expiration on resources (extended for debugging) .
98+ err = resource .Expire (900 )
7499 if err != nil {
75100 return nil , nil , err
76101 }
77102
78- viper .Set ("postgres_port" , resource .GetPort ("5432/tcp" ))
79- viper .Set ("postgres_hostname" , resource .Container .NetworkSettings .Gateway )
103+ // When running inside a container (e.g. CI), the postgres container is on
104+ // a different Docker network and we can't reach it via host port mapping.
105+ // Detect this and connect postgres to our network instead.
106+ pgHost := resource .Container .NetworkSettings .Gateway
107+ pgPort := resource .GetPort ("5432/tcp" )
108+ selfID := selfContainerID ()
109+ log .Infof ("selfContainerID: %q" , selfID )
110+ if selfID != "" {
111+ selfContainer , err := pool .Client .InspectContainer (selfID )
112+ if err != nil {
113+ return nil , nil , fmt .Errorf ("failed to inspect self container %s: %w" , selfID , err )
114+ }
115+ for netName , net := range selfContainer .NetworkSettings .Networks {
116+ if netName == "host" {
117+ continue
118+ }
119+ err := pool .Client .ConnectNetwork (net .NetworkID , docker.NetworkConnectionOptions {
120+ Container : resource .Container .ID ,
121+ })
122+ if err != nil {
123+ return nil , nil , fmt .Errorf ("failed to connect postgres to network %s: %w" , netName , err )
124+ }
125+ // Re-inspect to get the postgres container's IP on our network.
126+ updated , err := pool .Client .InspectContainer (resource .Container .ID )
127+ if err != nil {
128+ return nil , nil , fmt .Errorf ("failed to re-inspect postgres container: %w" , err )
129+ }
130+ resource .Container = updated
131+ if pgNet , ok := updated .NetworkSettings .Networks [netName ]; ok {
132+ pgHost = pgNet .IPAddress
133+ pgPort = "5432"
134+ log .Infof ("pgHost set to %s:%s via network %s" , pgHost , pgPort , netName )
135+ }
136+ break
137+ }
138+ }
139+ if pgHost == "" {
140+ pgHost = "localhost"
141+ }
142+ viper .Set ("postgres_port" , pgPort )
143+ viper .Set ("postgres_hostname" , pgHost )
80144 viper .Set ("postgres_db" , dbName )
81145 viper .Set ("postgres_username" , "postgres" )
82146 viper .Set ("postgres_password" , "secret" )
83147
148+ pool .MaxWait = 10 * time .Minute
84149 if err = pool .Retry (func () error {
85150 log .Info ("trying to connect" )
86151 db = pg .MustCreateDefaultPostgresDB ()
0 commit comments