blob: e09a9c178f4bbe92dafe862dc8b3341a263c59fc [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package options
8
9import (
10 "context"
11 "net"
12 "time"
13
14 "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
15 "github.com/mongodb/mongo-go-driver/event"
16 "github.com/mongodb/mongo-go-driver/mongo/readconcern"
17 "github.com/mongodb/mongo-go-driver/mongo/readpref"
18 "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
19 "github.com/mongodb/mongo-go-driver/x/mongo/driver/topology"
20 "github.com/mongodb/mongo-go-driver/x/network/connection"
21 "github.com/mongodb/mongo-go-driver/x/network/connstring"
22)
23
24// ContextDialer makes new network connections
25type ContextDialer interface {
26 DialContext(ctx context.Context, network, address string) (net.Conn, error)
27}
28
29// SSLOpt holds client SSL options.
30//
31// Enabled indicates whether SSL should be enabled.
32//
33// ClientCertificateKeyFile specifies the file containing the client certificate and private key
34// used for authentication.
35//
36// ClientCertificateKeyPassword provides a callback that returns a password used for decrypting the
37// private key of a PEM file (if one is provided).
38//
39// Insecure indicates whether to skip the verification of the server certificate and hostname.
40//
41// CaFile specifies the file containing the certificate authority used for SSL connections.
42type SSLOpt struct {
43 Enabled bool
44 ClientCertificateKeyFile string
45 ClientCertificateKeyPassword func() string
46 Insecure bool
47 CaFile string
48}
49
50// Credential holds auth options.
51//
52// AuthMechanism indicates the mechanism to use for authentication.
53// Supported values include "SCRAM-SHA-256", "SCRAM-SHA-1", "MONGODB-CR", "PLAIN", "GSSAPI", and "MONGODB-X509".
54//
55// AuthMechanismProperties specifies additional configuration options which may be used by certain
56// authentication mechanisms.
57//
58// AuthSource specifies the database to authenticate against.
59//
60// Username specifies the username that will be authenticated.
61//
62// Password specifies the password used for authentication.
63type Credential struct {
64 AuthMechanism string
65 AuthMechanismProperties map[string]string
66 AuthSource string
67 Username string
68 Password string
69}
70
71// ClientOptions represents all possbile options to configure a client.
72type ClientOptions struct {
73 TopologyOptions []topology.Option
74 ConnString connstring.ConnString
75 RetryWrites *bool
76 ReadPreference *readpref.ReadPref
77 ReadConcern *readconcern.ReadConcern
78 WriteConcern *writeconcern.WriteConcern
79 Registry *bsoncodec.Registry
80}
81
82// Client creates a new ClientOptions instance.
83func Client() *ClientOptions {
84 return &ClientOptions{
85 TopologyOptions: make([]topology.Option, 0),
86 }
87}
88
89// SetAppName specifies the client application name. This value is used by MongoDB when it logs
90// connection information and profile information, such as slow queries.
91func (c *ClientOptions) SetAppName(s string) *ClientOptions {
92 c.ConnString.AppName = s
93
94 return c
95}
96
97// SetAuth sets the authentication options.
98func (c *ClientOptions) SetAuth(auth Credential) *ClientOptions {
99 c.ConnString.AuthMechanism = auth.AuthMechanism
100 c.ConnString.AuthMechanismProperties = auth.AuthMechanismProperties
101 c.ConnString.AuthSource = auth.AuthSource
102 c.ConnString.Username = auth.Username
103 c.ConnString.Password = auth.Password
104
105 return c
106}
107
108// SetConnectTimeout specifies the timeout for an initial connection to a server.
109// If a custom Dialer is used, this method won't be set and the user is
110// responsible for setting the ConnectTimeout for connections on the dialer
111// themselves.
112func (c *ClientOptions) SetConnectTimeout(d time.Duration) *ClientOptions {
113 c.ConnString.ConnectTimeout = d
114 c.ConnString.ConnectTimeoutSet = true
115
116 return c
117}
118
119// SetDialer specifies a custom dialer used to dial new connections to a server.
120// If a custom dialer is not set, a net.Dialer with a 300 second keepalive time will be used by default.
121func (c *ClientOptions) SetDialer(d ContextDialer) *ClientOptions {
122 c.TopologyOptions = append(
123 c.TopologyOptions,
124 topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
125 return append(
126 opts,
127 topology.WithConnectionOptions(func(opts ...connection.Option) []connection.Option {
128 return append(
129 opts,
130 connection.WithDialer(func(connection.Dialer) connection.Dialer {
131 return d
132 }),
133 )
134 }),
135 )
136 }),
137 )
138
139 return c
140}
141
142// SetMonitor specifies a command monitor used to see commands for a client.
143func (c *ClientOptions) SetMonitor(m *event.CommandMonitor) *ClientOptions {
144 c.TopologyOptions = append(
145 c.TopologyOptions,
146 topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
147 return append(
148 opts,
149 topology.WithConnectionOptions(func(opts ...connection.Option) []connection.Option {
150 return append(
151 opts,
152 connection.WithMonitor(func(*event.CommandMonitor) *event.CommandMonitor {
153 return m
154 }),
155 )
156 }),
157 )
158 }),
159 )
160
161 return c
162}
163
164// SetHeartbeatInterval specifies the interval to wait between server monitoring checks.
165func (c *ClientOptions) SetHeartbeatInterval(d time.Duration) *ClientOptions {
166 c.ConnString.HeartbeatInterval = d
167 c.ConnString.HeartbeatIntervalSet = true
168
169 return c
170}
171
172// SetHosts specifies the initial list of addresses from which to discover the rest of the cluster.
173func (c *ClientOptions) SetHosts(s []string) *ClientOptions {
174 c.ConnString.Hosts = s
175
176 return c
177}
178
179// SetLocalThreshold specifies how far to distribute queries, beyond the server with the fastest
180// round-trip time. If a server's roundtrip time is more than LocalThreshold slower than the
181// the fastest, the driver will not send queries to that server.
182func (c *ClientOptions) SetLocalThreshold(d time.Duration) *ClientOptions {
183 c.ConnString.LocalThreshold = d
184 c.ConnString.LocalThresholdSet = true
185
186 return c
187}
188
189// SetMaxConnIdleTime specifies the maximum number of milliseconds that a connection can remain idle
190// in a connection pool before being removed and closed.
191func (c *ClientOptions) SetMaxConnIdleTime(d time.Duration) *ClientOptions {
192 c.ConnString.MaxConnIdleTime = d
193 c.ConnString.MaxConnIdleTimeSet = true
194
195 return c
196}
197
198// SetMaxPoolSize specifies the max size of a server's connection pool.
199func (c *ClientOptions) SetMaxPoolSize(u uint16) *ClientOptions {
200 c.ConnString.MaxPoolSize = u
201 c.ConnString.MaxPoolSizeSet = true
202
203 return c
204}
205
206// SetReadConcern specifies the read concern.
207func (c *ClientOptions) SetReadConcern(rc *readconcern.ReadConcern) *ClientOptions {
208 c.ReadConcern = rc
209
210 return c
211}
212
213// SetReadPreference specifies the read preference.
214func (c *ClientOptions) SetReadPreference(rp *readpref.ReadPref) *ClientOptions {
215 c.ReadPreference = rp
216
217 return c
218}
219
220// SetRegistry specifies the bsoncodec.Registry.
221func (c *ClientOptions) SetRegistry(registry *bsoncodec.Registry) *ClientOptions {
222 c.Registry = registry
223
224 // add registry to the server options so that it will be used for the cursors built by this client
225 c.TopologyOptions = append(
226 c.TopologyOptions,
227 topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
228 return append(
229 opts,
230 topology.WithRegistry(func(*bsoncodec.Registry) *bsoncodec.Registry {
231 return registry
232 }),
233 )
234 }),
235 )
236
237 return c
238}
239
240// SetReplicaSet specifies the name of the replica set of the cluster.
241func (c *ClientOptions) SetReplicaSet(s string) *ClientOptions {
242 c.ConnString.ReplicaSet = s
243
244 return c
245}
246
247// SetRetryWrites specifies whether the client has retryable writes enabled.
248func (c *ClientOptions) SetRetryWrites(b bool) *ClientOptions {
249 c.RetryWrites = &b
250
251 return c
252}
253
254// SetServerSelectionTimeout specifies a timeout in milliseconds to block for server selection.
255func (c *ClientOptions) SetServerSelectionTimeout(d time.Duration) *ClientOptions {
256 c.ConnString.ServerSelectionTimeout = d
257 c.ConnString.ServerSelectionTimeoutSet = true
258
259 return c
260}
261
262// SetSingle specifies whether the driver should connect directly to the server instead of
263// auto-discovering other servers in the cluster.
264func (c *ClientOptions) SetSingle(b bool) *ClientOptions {
265 if b {
266 c.ConnString.Connect = connstring.SingleConnect
267 } else {
268 c.ConnString.Connect = connstring.AutoConnect
269 }
270 c.ConnString.ConnectSet = true
271
272 return c
273}
274
275// SetSocketTimeout specifies the time in milliseconds to attempt to send or receive on a socket
276// before the attempt times out.
277func (c *ClientOptions) SetSocketTimeout(d time.Duration) *ClientOptions {
278 c.ConnString.SocketTimeout = d
279 c.ConnString.SocketTimeoutSet = true
280
281 return c
282}
283
284// SetSSL sets SSL options.
285func (c *ClientOptions) SetSSL(ssl *SSLOpt) *ClientOptions {
286 c.ConnString.SSL = ssl.Enabled
287 c.ConnString.SSLSet = true
288
289 if ssl.ClientCertificateKeyFile != "" {
290 c.ConnString.SSLClientCertificateKeyFile = ssl.ClientCertificateKeyFile
291 c.ConnString.SSLClientCertificateKeyFileSet = true
292 }
293
294 if ssl.ClientCertificateKeyPassword != nil {
295 c.ConnString.SSLClientCertificateKeyPassword = ssl.ClientCertificateKeyPassword
296 c.ConnString.SSLClientCertificateKeyPasswordSet = true
297 }
298
299 c.ConnString.SSLInsecure = ssl.Insecure
300 c.ConnString.SSLInsecureSet = true
301
302 if ssl.CaFile != "" {
303 c.ConnString.SSLCaFile = ssl.CaFile
304 c.ConnString.SSLCaFileSet = true
305 }
306
307 return c
308}
309
310// SetWriteConcern sets the write concern.
311func (c *ClientOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *ClientOptions {
312 c.WriteConcern = wc
313
314 return c
315}
316
317// MergeClientOptions combines the given connstring and *ClientOptions into a single *ClientOptions in a last one wins
318// fashion. The given connstring will be used for the default options, which can be overwritten using the given
319// *ClientOptions.
320func MergeClientOptions(cs connstring.ConnString, opts ...*ClientOptions) *ClientOptions {
321 c := Client()
322 c.ConnString = cs
323
324 for _, opt := range opts {
325 if opt == nil {
326 continue
327 }
328 c.TopologyOptions = append(c.TopologyOptions, opt.TopologyOptions...)
329
330 if an := opt.ConnString.AppName; an != "" {
331 c.ConnString.AppName = an
332 }
333 if am := opt.ConnString.AuthMechanism; len(am) != 0 {
334 c.ConnString.AuthMechanism = am
335 }
336 if amp := opt.ConnString.AuthMechanismProperties; amp != nil {
337 c.ConnString.AuthMechanismProperties = amp
338 }
339 if as := opt.ConnString.AuthSource; len(as) != 0 {
340 c.ConnString.AuthSource = as
341 }
342 if u := opt.ConnString.Username; len(u) != 0 {
343 c.ConnString.Username = u
344 }
345 if p := opt.ConnString.Password; len(p) != 0 {
346 c.ConnString.Password = p
347 }
348 if opt.ConnString.ConnectTimeoutSet {
349 c.ConnString.ConnectTimeoutSet = true
350 c.ConnString.ConnectTimeout = opt.ConnString.ConnectTimeout
351 }
352 if opt.ConnString.HeartbeatIntervalSet {
353 c.ConnString.HeartbeatIntervalSet = true
354 c.ConnString.HeartbeatInterval = opt.ConnString.HeartbeatInterval
355 }
356 if h := opt.ConnString.Hosts; h != nil {
357 c.ConnString.Hosts = h
358 }
359 if opt.ConnString.LocalThresholdSet {
360 c.ConnString.LocalThresholdSet = true
361 c.ConnString.LocalThreshold = opt.ConnString.LocalThreshold
362 }
363 if opt.ConnString.MaxConnIdleTimeSet {
364 c.ConnString.MaxConnIdleTimeSet = true
365 c.ConnString.MaxConnIdleTime = opt.ConnString.MaxConnIdleTime
366 }
367 if opt.ConnString.MaxPoolSizeSet {
368 c.ConnString.MaxPoolSizeSet = true
369 c.ConnString.MaxPoolSize = opt.ConnString.MaxPoolSize
370 }
371 if opt.ReadConcern != nil {
372 c.ReadConcern = opt.ReadConcern
373 }
374 if opt.ReadPreference != nil {
375 c.ReadPreference = opt.ReadPreference
376 }
377 if opt.Registry != nil {
378 c.Registry = opt.Registry
379 }
380 if rs := opt.ConnString.ReplicaSet; rs != "" {
381 c.ConnString.ReplicaSet = rs
382 }
383 if opt.RetryWrites != nil {
384 c.RetryWrites = opt.RetryWrites
385 }
386 if opt.ConnString.ServerSelectionTimeoutSet {
387 c.ConnString.ServerSelectionTimeoutSet = true
388 c.ConnString.ServerSelectionTimeout = opt.ConnString.ServerSelectionTimeout
389 }
390 if opt.ConnString.ConnectSet {
391 c.ConnString.ConnectSet = true
392 c.ConnString.Connect = opt.ConnString.Connect
393 }
394 if opt.ConnString.SocketTimeoutSet {
395 c.ConnString.SocketTimeoutSet = true
396 c.ConnString.SocketTimeout = opt.ConnString.SocketTimeout
397 }
398 if opt.ConnString.SSLSet {
399 c.ConnString.SSLSet = true
400 c.ConnString.SSL = opt.ConnString.SSL
401 }
402 if opt.ConnString.SSLClientCertificateKeyFileSet {
403 c.ConnString.SSLClientCertificateKeyFileSet = true
404 c.ConnString.SSLClientCertificateKeyFile = opt.ConnString.SSLClientCertificateKeyFile
405 }
406 if opt.ConnString.SSLClientCertificateKeyPasswordSet {
407 c.ConnString.SSLClientCertificateKeyPasswordSet = true
408 c.ConnString.SSLClientCertificateKeyPassword = opt.ConnString.SSLClientCertificateKeyPassword
409 }
410 if opt.ConnString.SSLInsecureSet {
411 c.ConnString.SSLInsecureSet = true
412 c.ConnString.SSLInsecure = opt.ConnString.SSLInsecure
413 }
414 if opt.ConnString.SSLCaFileSet {
415 c.ConnString.SSLCaFileSet = true
416 c.ConnString.SSLCaFile = opt.ConnString.SSLCaFile
417 }
418 if opt.WriteConcern != nil {
419 c.WriteConcern = opt.WriteConcern
420 }
421 }
422
423 return c
424}