Skip to content

Commit a963bcf

Browse files
committed
Handle docker in docker side car container access
Signed-off-by: Dom Del Nano <ddelnano@gmail.com>
1 parent e2c3e25 commit a963bcf

2 files changed

Lines changed: 136 additions & 6 deletions

File tree

src/shared/services/pgtest/pgtest.go

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
package pgtest
2020

2121
import (
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.
3762
func 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()

src/utils/testingutils/docker/elastic.go

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,39 @@
1919
package docker
2020

2121
import (
22+
"bufio"
2223
"fmt"
24+
"os"
25+
"regexp"
26+
"time"
2327

2428
"github.com/olivere/elastic/v7"
2529
"github.com/ory/dockertest/v3"
2630
"github.com/ory/dockertest/v3/docker"
2731
log "github.com/sirupsen/logrus"
2832
)
2933

34+
// selfContainerID returns the current Docker container ID by parsing
35+
// /proc/self/mountinfo. Docker bind-mounts /etc/hostname from
36+
// /var/lib/docker/containers/<id>/hostname, exposing the container ID.
37+
// Returns empty string if not running inside a Docker container.
38+
func selfContainerID() string {
39+
f, err := os.Open("/proc/self/mountinfo")
40+
if err != nil {
41+
return ""
42+
}
43+
defer f.Close()
44+
45+
re := regexp.MustCompile(`/containers/([a-f0-9]{64})/hostname`)
46+
scanner := bufio.NewScanner(f)
47+
for scanner.Scan() {
48+
if m := re.FindStringSubmatch(scanner.Text()); m != nil {
49+
return m[1]
50+
}
51+
}
52+
return ""
53+
}
54+
3055
func connectElastic(esURL string, esUser string, esPass string) (*elastic.Client, error) {
3156
es, err := elastic.NewClient(elastic.SetURL(esURL),
3257
elastic.SetBasicAuth(esUser, esPass),
@@ -104,12 +129,52 @@ func SetupElastic() (*elastic.Client, func(), error) {
104129
return nil, cleanup, err
105130
}
106131

107-
clientPort := resource.GetPort("9200/tcp")
132+
// When running inside a container (e.g. CI), the ES container is on
133+
// a different Docker network and we can't reach it via host port mapping.
134+
// Detect this and connect ES to our network instead.
135+
esHost := resource.Container.NetworkSettings.Gateway
136+
esPort := resource.GetPort("9200/tcp")
137+
selfID := selfContainerID()
138+
log.Infof("selfContainerID: %q", selfID)
139+
if selfID != "" {
140+
selfContainer, err := pool.Client.InspectContainer(selfID)
141+
if err != nil {
142+
return nil, cleanup, fmt.Errorf("failed to inspect self container %s: %w", selfID, err)
143+
}
144+
for netName, net := range selfContainer.NetworkSettings.Networks {
145+
if netName == "host" {
146+
continue
147+
}
148+
err := pool.Client.ConnectNetwork(net.NetworkID, docker.NetworkConnectionOptions{
149+
Container: resource.Container.ID,
150+
})
151+
if err != nil {
152+
return nil, cleanup, fmt.Errorf("failed to connect ES to network %s: %w", netName, err)
153+
}
154+
// Re-inspect to get the ES container's IP on our network.
155+
updated, err := pool.Client.InspectContainer(resource.Container.ID)
156+
if err != nil {
157+
return nil, cleanup, fmt.Errorf("failed to re-inspect ES container: %w", err)
158+
}
159+
resource.Container = updated
160+
if esNet, ok := updated.NetworkSettings.Networks[netName]; ok {
161+
esHost = esNet.IPAddress
162+
esPort = "9200"
163+
log.Infof("esHost set to %s:%s via network %s", esHost, esPort, netName)
164+
}
165+
break
166+
}
167+
}
168+
if esHost == "" {
169+
esHost = "localhost"
170+
}
171+
172+
pool.MaxWait = 10 * time.Minute
108173
var client *elastic.Client
109174
err = pool.Retry(func() error {
110175
var err error
111176
client, err = connectElastic(fmt.Sprintf("http://%s:%s",
112-
resource.Container.NetworkSettings.Gateway, clientPort), "elastic", esPass)
177+
esHost, esPort), "elastic", esPass)
113178
if err != nil {
114179
log.WithError(err).Errorf("Failed to connect to elasticsearch.")
115180
}

0 commit comments

Comments
 (0)