Uploaded image for project: 'Go Driver'
  1. Go Driver
  2. GODRIVER-1174

Topology will prefer a non-resolvable hostname over one known to resolve

    • Type: Icon: Bug Bug
    • Resolution: Gone away
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • 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:

      Unable to find source-code formatter for language: golang. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      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.

            Assignee:
            isabella.siu@mongodb.com Isabella Siu (Inactive)
            Reporter:
            john.morales@mongodb.com John Morales (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: