-
Type: Bug
-
Resolution: Gone away
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Server Discovery and Monitoring
-
None
-
Environment:mongo-driver @ 60e65d0f2639c81f74a92904fcd10900e37b9be6 (tip of repo as of June 28)
macos
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.