Cannot create index for MongoDB replica set: ReplicaSetNoPrimary - mongodb

I am writing integration testing for my Go program. When I try to initiate my MongoDB (with Docker) running in replica set, it raise error:
server selection error: server selection timeout, current topology:
{
Type: ReplicaSetNoPrimary,
Servers: [
{
Addr: b3ec1125321a:27017,
Type: Unknown,
Last error: connection() error occurred during connection handshake: dial tcp: lookup b3ec1125321a on 10.225.109.87:53: no such host
},
]
}
So I try to create a minimal runnable code as below with comment:
package main
import (
"bytes"
"context"
"errors"
"fmt"
"net"
"os/exec"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// getDockerPath returns the path for docker.
func getDockerPath() (string, error) {
return exec.LookPath("docker")
}
// getPort returns a useable port. (should use it as soon as you can)
func getPort() (int, error) {
l, err := net.Listen("tcp", ":0")
if err != nil {
return 0, fmt.Errorf("listen to port 0: %w", err)
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
// runMongo will run a MongoDB container in docker.
func runMongo(ctx context.Context) error {
dockerPath, err := getDockerPath()
if err != nil {
return fmt.Errorf("get docker path: %w", err)
}
mongoPort, err := getPort()
if err != nil {
return fmt.Errorf("get mongo port: %w", err)
}
mongoURL := fmt.Sprintf("mongodb://127.0.0.1:%d", mongoPort)
fmt.Printf("Starting a mongoDB listening on %s\n\n", mongoURL)
// Run MongoDB - build command and run.
args := []string{
"run", "-d", "-p", fmt.Sprintf("%d:27017", mongoPort),
"mongo",
"mongod", "--replSet=rs0",
}
startCmd := exec.CommandContext(ctx, dockerPath, args...)
stdout := &bytes.Buffer{}
startCmd.Stdout = stdout
if err := startCmd.Run(); err != nil {
return fmt.Errorf("run MongoDB container by docker: %w", err)
}
// Get the Docker container name.
containerName, err := stdout.ReadString('\n')
for err != nil {
containerName, err = stdout.ReadString('\n')
}
containerName = containerName[:6]
// **********************************************************************
// NOTICE: When I remove the code below to initiate the MongoDB's Replica
// Set. And remove the argument `--replSet rs0`, it works.
// **********************************************************************
//
// Initiate Mongo's Replica Set.
args = []string{
"exec", containerName,
"mongo", "--eval", "rs.initiate();",
}
err = errors.New("in loop")
for err != nil {
<-time.After(1 * time.Second)
initCmd := exec.CommandContext(ctx, dockerPath, args...)
fmt.Println(initCmd)
err = initCmd.Run()
if err != nil {
fmt.Println(err)
}
}
// Init MongoDB before use it.
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoURL))
if err != nil {
return fmt.Errorf("cannot connect to MongoDB: %w", err)
}
indexName := "Namespace's name's unique index"
True := true
index, err := client.Database("tmp").Collection("namespace").Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{Key: "name", Value: 1}},
Options: &options.IndexOptions{
Name: &indexName,
Unique: &True,
},
})
if err != nil {
return fmt.Errorf("create index for namespace: %w", err)
}
fmt.Println(index)
return nil
}
func main() {
err := runMongo(context.Background())
if err != nil {
fmt.Printf("Fail to run MongoDB: %v\n", err)
}
}
When I try to run, it throw an error:
$ go run .
Starting a mongoDB listening on mongodb://127.0.0.1:29597
/usr/bin/docker exec b3ec11 mongo --eval rs.initiate();
Fail to run MongoDB: create index for namespace: server selection error: server selection timeout, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: b3ec1125321a:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup b3ec1125321a on 10.225.109.87:53: no such host }, ] }
I try to search on Google. But still cannot find a solution.
UPDATE: I can use mongosh to do it without any error:
$ mongosh mongodb://127.0.0.1:29597
> use tmp
> ns = db.getCollection("namespace")
> ns.createIndex({name: 1}, {unique: true, name: "Namespace's name's unique index"})
And this really worry me a lot - I cannot get why I can use mongosh but not the go-driver of MongoDB.
It tells me that now it is ReplicaSetNoPrimary. But I try to use mongosh to connect it and run rs.isMaster() - it tells me that the only running MongoDB node IS the master node.

I try to let the MongoDB use the network host but not the bridge, and then it works:
--- another.go 2022-08-28 17:14:58.536381918 +0800
+++ main.go 2022-08-28 17:16:06.193467707 +0800
## -40,13 +40,13 ##
return fmt.Errorf("get mongo port: %w", err)
}
mongoURL := fmt.Sprintf("mongodb://127.0.0.1:%d", mongoPort)
- fmt.Printf("Starting a mongoDB listening on %s\n\n", mongoURL)
+ fmt.Printf("Starting a mongoDB listening on %s [on host network]\n\n", mongoURL)
// Run MongoDB - build command and run.
args := []string{
- "run", "-d", "-p", fmt.Sprintf("%d:27017", mongoPort),
+ "run", "-d", "--net=host",
"mongo",
- "mongod", "--replSet=rs0",
+ "mongod", "--replSet=rs0", fmt.Sprintf("--port=%d", mongoPort),
}
startCmd := exec.CommandContext(ctx, dockerPath, args...)
stdout := &bytes.Buffer{}
## -70,7 +70,7 ##
// Initiate Mongo's Replica Set.
args = []string{
"exec", containerName,
- "mongo", "--eval", "rs.initiate();",
+ "mongo", "--eval", "rs.initiate();", mongoURL,
}
err = errors.New("in loop")
for err != nil {
But I still do not know why I cannot let it work in bridge network. [Waiting for another answer still...]

Related

how to connect with mongodb in go using atlas?

I am getting a server selection timeout while connecting to mongodb.Any help is appreciated.
selection error: server selection timeout, current topology: { Type:
ReplicaSetNoPrimary, Servers: [{ Addr:
ac-pjyudwq-shard-00-01.1bnb2bm.mongodb.net:27017, Type: Unknown, Last
error: dial tcp 3.6.207.111:27017: i/o timeout }, { Addr:
ac-pjyudwq-shard-00-00.1bnb2bm.mongodb.net:27017, Type: Unknown, Last
error: dial tcp 3.7.150.83:27017: i/o timeout }, { Addr:
ac-pjyudwq-shard-00-02.1bnb2bm.mongodb.net:27017, Type: Unknown, Last
error: dial tcp 3.7.137.42:27017: i/o timeout }, ] } exit status 1
Code that I used for the connection
const MONGOURL = "mongodb+srv://sai:sai#cluster0.1bnb2bm.mongodb.net/?retryWrites=true&w=majority"
var collection *mongo.Collection
func init() {
fmt.Println("in the init function") var databasename string = "GOAPI"
var collectionname string = "Movies"
client, err: = mongo.Connect(context.TODO(), options.Client().ApplyURI(MONGOURL)) if err != nil {
fmt.Println("unable to get mongo connection ") log.Fatal(err)
}
collection = ( * mongo.Collection)(client.Database(databasename).Collection(collectionname)) fmt.Println("sucessfully collection is created ") doc: = Movie {
Name: "rrr",
Watched: false,
Rating: 9,
Id: "12121"
}
result, err: = collection.InsertOne(context.Background(), doc) if err != nil {
log.Fatal("hey unable to insert one ", err)
}
fmt.Println("sucessfully added : ", result.InsertedID)
// mongo.Connect()`your text`
}
I am hosting my test Atlas cluster on AWS so I wanted to have similar credential management to the AWS process. From the AWS credentials page:
The default provider chain looks for credentials in the following order:
Environment variables.
Shared credentials file.
If your application is running on an Amazon EC2 instance, IAM role for Amazon EC2.
Therefore, I wanted to implement the environment veriable for my simple login to Atlas example. Code below assumes that the following line has been issued at the command line
export MONGO_PW='<your Atlas admin user password>'
Then the following program will verify your connection
package main
import (
"context"
"fmt"
"os"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var username = "<username>"
var host1 = "<atlas host>" // of the form foo.mongodb.net
func main() {
ctx := context.TODO()
pw, ok := os.LookupEnv("MONGO_PW")
if !ok {
fmt.Println("error: unable to find MONGO_PW in the environment")
os.Exit(1)
}
mongoURI := fmt.Sprintf("mongodb+srv://%s:%s#%s", username, pw, host1)
fmt.Println("connection string is:", mongoURI)
// Set client options and connect
clientOptions := options.Client().ApplyURI(mongoURI)
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = client.Ping(ctx, nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Connected to MongoDB!")
}
From here the rest of the tutorial linked in my original question goes smoothly.

MongoDB error with website connection after tried to connect with mongodb database status code 403

I have a problem with mongodb website.
Below i send image with my issue. I built project in Golang where i want to connect with mongodb and if i tried I got error
server selection error: context deadline exceeded, current topology: { Type: Unknown, Servers: [{ Addr: localhost:27017, Type: Unknown, Last error: dial tcp [::1]:27017: connect: connection refused }, ] }
Here I have code where i trying to connect with mongo client
func Connect() *DB {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
err = client.Connect(ctx)
return &DB{
client: client,
}
}
Error on site
Not sure to which MongoDB you are trying to connect. In your code example, the DB is on your local machine.
Your code is missing the DB credentials.
You can try the following code to connect to the DB and verify your connectivity:
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://admin:password#localhost:27017"))
if err != nil {
log.Fatal(err)
}
if err = client.Ping(context.TODO(), readpref.Primary()); err != nil {
log.Fatal(err)
}
log.Println("Connected to MongoDB")

Cannot connect to mongodb Error error occurred during connection

im trying to connect to my mongodb from my api written in golang
but every time i run my app it gives me this error:
2022/12/06 19:09:25 server selection error: server selection timeout, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: ac-tqorttq-shard-00-02.atpezds.mongodb.net:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp 52.28.222.2:27017: i/o timeout }, { Addr: ac-tqorttq-shard-00-00.atpezds.mongodb.net:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp 18.197.37.129:27017: i/o timeout }, { Addr: ac-tqorttq-shard-00-01.atpezds.mongodb.net:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp 18.195.134.220:27017: i/o timeout }, ] }
my code:
func init() {
clientOptions := options.Client().ApplyURI(configs.GetEnv("MONGOURI"))
client, err := mongo.Connect(context.TODO(), clientOptions)
checkErr(err)
err = client.Ping(context.TODO(), nil)
checkErr(err)
fmt.Println("connected to database successfully")
notesCollection = openCollection("notes_collection")
userCollection = openCollection("user_collection")
}
i tried to remove the "+srv" from the connection string then
it gives me this error:
2022/12/06 19:16:46 server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: cluster0.atpezds.mongodb.net:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup cluster0.atpezds.mongodb.net: No address associated with hostname }, ] }
hope you guys help me
and thanks
func main() {
client, err := mongo.NewClient(options.Client().ApplyURI("<ATLAS_URI_HERE>"))
if err != nil {
log.Fatal(err)
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
err = client.Connect(ctx)
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
err = client.Ping(ctx, readpref.Primary())
if err != nil {
log.Fatal(err)
}
databases, err := client.ListDatabaseNames(ctx, bson.M{})
if err != nil {
log.Fatal(err)
}
fmt.Println(databases)
}
Check that you are using the correct username and password for your database user, and that you are connecting to the correct database deployment. Check that you are specifying the correct authSource database in your connection string.
Hope this helps!!

mongo golang driver sever selection timeout

I have launched the mongodb helm chart (standalone mode , set rootPassword, username, password in values.yaml) and I tried launching just the docker container too, I'm hitting the same error.
func (s *Session) ConnectToDB(u, p string) (*mongo.Client, error) {
var err error
uri := fmt.Sprintf("%s:%s", mongoDBURL, mongoDBPort)
auth := new(options.Credential)
auth.Username = u
auth.Password = p
opts := options.Client().ApplyURI(uri).SetAuth(*auth)
opts.SetConnectTimeout(-1)
opts.SetDirect(true)
s.Ctx = context.TODO()
//opts.SetMaxPoolSize(5) # TODO
if s.Client, err = mongo.Connect(s.Ctx, opts); err != nil {
msg := fmt.Sprintf("error connecting to mongo: %v", err)
log.Printf(msg)
return nil, fmt.Errorf(msg)
}
err = s.Client.Ping(s.Ctx, nil)
if err != nil {
log.Fatal(err). <<<<< Fails with error
}
s.Collection = getCollection(s
)
The URL:port is
mongoDBPort = "27017"
mongoDBURL = "localhost"
I have tried, "mongodb://mongodb.spektra-system.svc.cluster.local" too. The Client ping fails with error
server selection error: server selection timeout, current topology: { Type: Single, Servers: [{ Addr: localhost:27017, Type: Unknown, Average RTT: 0, Last error
: connection() error occured during connection handshake: dial tcp: i/o timeout }, ] }
Should I set something in the values.yaml ??? Not sure why this fails. I'm using mongo golang diver 1.5
Googling around I found directConnect=true is required, didn't help .

unable to authenticate with mongodb golang driver

I'm using mongodb community version 4.2.13 and go driver version 1.5.
My go application is running on the same host as db, but getting the following error when trying to make a connection:
connection() error occured during connection handshake: auth error:
sasl conversation error: unable to authenticate using mechanism
"SCRAM-SHA-256": (AuthenticationFailed) Authentication failed.
Here is how I created the admin account:
use admin
db.createUser({
user: "admin1",
pwd: "passwd12#$",
roles: ["root"],
mechanisms: ["SCRAM-SHA-256"]
})
db.system.users.update(
{ _id: "admin.admin1", "db": "admin" },
{
$addToSet: {
authenticationRestrictions: { clientSource: ["127.0.0.1"] }
}
}
)
Go app code snippet
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
uri := fmt.Sprintf(
"mongodb://%s:%s#%s:%d/admin?authSource=admin&authMechanism=SCRAM-SHA-256",
"admin1",
"passwd12#$",
"127.0.0.1",
27017,
)
// Prints "mongodb://admin1:passwd12#$#127.0.0.1:27017/admin?authSource=admin&authMechanism=SCRAM-SHA-256"
fmt.Println(uri)
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
defer cancel()
client, err := mongo.Connect(
ctx,
options.Client().ApplyURI(uri),
)
if err != nil {
panic(err)
}
defer func() {
err = client.Disconnect(ctx)
if err != nil {
panic(err)
}
}()
err = client.Ping(ctx, nil)
if err != nil {
panic(err)
}
fmt.Println("pinged")
}
I tried the following, but all of them didn't work:
Encoding username and password using url.QueryEscape
Trying "localhost" instead of "127.0.0.1"
Removing "authMechanism=SCRAM-SHA-256" in uri
As a side note, connecting to the Mongo shell with the exact same uri, and that worked.
Add ssl=false to your uri. Worked for me
Based on MongoDB documentation for the authentication process, there is a parameter to identify which database is used for authentication besides the target database on the URI.
While in mongoshell you can use this line
mongo "mongodb://Admin:${DBPASSWORD}#<host>:<port>/admin?authSource=admin"
I used that information to add ?authSource=admin to my CONNECTION_URL
CONNECTION_URL=mongodb://root:example#mongo:27017/my_database?retryWrites=true&w=majority&authSource=admin
That worked for me. Hope it does for you too.
For detailed information please review https://www.mongodb.com/features/mongodb-authentication
You could try using 'options.Credential' to pass the authentication settings.
Seems like a cleaner way than formatting an URI that needs to be parsed later on.
https://docs.mongodb.com/drivers/go/current/fundamentals/auth/
clientOpts := options.Client().SetHosts(
[]string{"localhost:27017"},
).SetAuth(
options.Credential{
AuthSource: "<authenticationDb>",
AuthMechanism: "SCRAM-SHA-256",
Username: "<username>",
Password: "<password>",
}
)
client, err := mongo.Connect(context.TODO(), clientOpts)