Details
-
Bug
-
Resolution: Gone away
-
Major - P3
-
None
-
None
-
None
-
mongo-driver @ 60e65d0f2639c81f74a92904fcd10900e37b9be6 (tip of repo as of June 28)
macos
Description
I'm not entirely positive this is an expected behavior, however I do have reproducer programs in Java and Go where the Java program is successful but equivalent golang program is not.
Starting State (this can be setup locally on just a macbook, but I think is easier to illustrate in an environment with 2 servers):
- Host A - server
- hostname = "hostname.local"
- single node replica set
- rs.conf() is configured with members[0].host="hostname.local:27017"
- Host B - client
- Attempt to connect to the mongod on Host A using different hostname, such as one that's fully qualified: "hostname.acme.com:27017"
- From Host B, "hostname.acme.com" is resolvable to address of Host A but "hostname.local" does not resolve
Expected: client communication is fine, because we found the server on Host A using the seed list entry "hostname.acme.com:27017" which is valid.
Actual: A Java program is successful but a golang program fails, appearing to initially connect and discover the configuration with hostname.local:27017, and then exclusively try and use hostname.local:27017 for all operations (which all fail because it's not resolvable from Host B).
Java Program (successfully prints ping command response):
@Test |
public void testSDAM() throws Exception { |
try (final MongoClient client = new MongoClient(new MongoClientURI("mongodb://John-Morales-MacBook-Pro.local:10001"))) { |
System.out.println(client.getDatabase("admin").runCommand(new Document("ping", 1))); |
}
|
}
|
go-driver program and output:
package main
|
|
|
import (
|
"context"
|
"flag"
|
"fmt"
|
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/readpref"
|
"time"
|
)
|
|
|
func ping(client *mongo.Client) error {
|
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
|
defer cancel()
|
return client.Ping(ctx, nil)
|
}
|
|
|
func main() {
|
host := flag.String("host", "localhost", "Hostname to ping")
|
port := flag.Int("port", 27017, "Port to ping")
|
flag.Parse()
|
|
|
var addrs string = fmt.Sprintf("%v:%v", *host, *port)
|
hosts := []string{fmt.Sprintf("%v:%v", *host, *port)}
|
|
|
clientOptions := options.Client()
|
clientOptions.SetHosts(hosts).SetConnectTimeout(5 * time.Second).SetSocketTimeout(5 * time.Second).SetServerSelectionTimeout(2 * time.Second)
|
|
|
rp, err := readpref.New(readpref.PrimaryMode)
|
clientOptions.SetReadPreference(rp)
|
|
|
client, err := mongo.NewClient(clientOptions.ApplyURI(fmt.Sprintf("mongodb://%v", addrs)))
|
if err != nil {
|
panic(nil)
|
}
|
|
|
if clientOptions.SocketTimeout != nil {
|
ctx, cancel := context.WithTimeout(context.Background(), *clientOptions.SocketTimeout)
|
defer cancel()
|
err = client.Connect(ctx)
|
} else {
|
err = client.Connect(context.Background())
|
}
|
|
|
if err != nil {
|
client.Disconnect(context.Background())
|
panic(err)
|
}
|
|
|
err = ping(client)
|
if err != nil {
|
client.Disconnect(context.Background())
|
panic(err)
|
}
|
|
|
fmt.Println(client.Disconnect(context.Background()))
|
}
|
Go program output:
$ go run -v godriver.go -host John-Morales-MacBook-Pro.local -port 10001
|
panic: server selection error: server selection timeout
|
current topology: Type: ReplicaSetNoPrimary
|
Servers:
|
Addr: does-not-exist:10001, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection() : dial tcp: lookup does-not-exist: no such host
|
|
|
goroutine 1 [running]:
|
main.main()
|
/Users/johnmorales/projects/mms-backup.git/goagent/src/10gen.com/backup-agent/play/godriver.go:54 +0x732
|
exit status 2
|
Additional note: if the connection URI is instead:
client, err := mongo.NewClient(clientOptions.ApplyURI(fmt.Sprintf("mongodb://%v/?connect=direct", addrs)))
... then the go program does work.