-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
mongodbhelper.go
141 lines (125 loc) · 3.46 KB
/
mongodbhelper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package mongodb
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/url"
"os"
"strconv"
"strings"
"testing"
"time"
"github.com/hashicorp/vault/helper/testhelpers/docker"
"gopkg.in/mgo.v2"
)
// PrepareTestContainer calls PrepareTestContainerWithDatabase without a
// database name value, which results in configuring a database named "test"
func PrepareTestContainer(t *testing.T, version string) (cleanup func(), retURL string) {
return PrepareTestContainerWithDatabase(t, version, "")
}
// PrepareTestContainerWithDatabase configures a test container with a given
// database name, to test non-test/admin database configurations
func PrepareTestContainerWithDatabase(t *testing.T, version, dbName string) (func(), string) {
if os.Getenv("MONGODB_URL") != "" {
return func() {}, os.Getenv("MONGODB_URL")
}
runner, err := docker.NewServiceRunner(docker.RunOptions{
ImageRepo: "mongo",
ImageTag: version,
Ports: []string{"27017/tcp"},
})
if err != nil {
t.Fatalf("could not start docker mongo: %s", err)
}
svc, err := runner.StartService(context.Background(), func(ctx context.Context, host string, port int) (docker.ServiceConfig, error) {
connURL := fmt.Sprintf("mongodb://%s:%d", host, port)
if dbName != "" {
connURL = fmt.Sprintf("%s/%s", connURL, dbName)
}
dialInfo, err := ParseMongoURL(connURL)
if err != nil {
return nil, err
}
session, err := mgo.DialWithInfo(dialInfo)
if err != nil {
return nil, err
}
defer session.Close()
session.SetSyncTimeout(1 * time.Minute)
session.SetSocketTimeout(1 * time.Minute)
err = session.Ping()
if err != nil {
return nil, err
}
return docker.NewServiceURLParse(connURL)
})
if err != nil {
t.Fatalf("could not start docker mongo: %s", err)
}
return svc.Cleanup, svc.Config.URL().String()
}
// ParseMongoURL will parse a connection string and return a configured dialer
func ParseMongoURL(rawURL string) (*mgo.DialInfo, error) {
url, err := url.Parse(rawURL)
if err != nil {
return nil, err
}
info := mgo.DialInfo{
Addrs: strings.Split(url.Host, ","),
Database: strings.TrimPrefix(url.Path, "/"),
Timeout: 10 * time.Second,
}
if url.User != nil {
info.Username = url.User.Username()
info.Password, _ = url.User.Password()
}
query := url.Query()
for key, values := range query {
var value string
if len(values) > 0 {
value = values[0]
}
switch key {
case "authSource":
info.Source = value
case "authMechanism":
info.Mechanism = value
case "gssapiServiceName":
info.Service = value
case "replicaSet":
info.ReplicaSetName = value
case "maxPoolSize":
poolLimit, err := strconv.Atoi(value)
if err != nil {
return nil, errors.New("bad value for maxPoolSize: " + value)
}
info.PoolLimit = poolLimit
case "ssl":
// Unfortunately, mgo doesn't support the ssl parameter in its MongoDB URI parsing logic, so we have to handle that
// ourselves. See https://github.com/go-mgo/mgo/issues/84
ssl, err := strconv.ParseBool(value)
if err != nil {
return nil, errors.New("bad value for ssl: " + value)
}
if ssl {
info.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
return tls.Dial("tcp", addr.String(), &tls.Config{})
}
}
case "connect":
if value == "direct" {
info.Direct = true
break
}
if value == "replicaSet" {
break
}
fallthrough
default:
return nil, errors.New("unsupported connection URL option: " + key + "=" + value)
}
}
return &info, nil
}