Connecting to MongoDB Atlas
marzhaev opened this issue · 9 comments
I have migrated from self hosted MongoDB to MongoDB Atlas hosted replica. There seems to be a problem authenticating my Yesod application which throws:
Error handler errored out: InternalError "ConnectionFailure <socket: 22>: hGetBuf: resource vanished (Connection reset by peer)"
Having migrated Ruby and NodeJS application, I believe the problem is the configuration needs to
include:
- SSL flag to be set to truth.
- AuthSource to be specified.
MongoDB's official manual at https://docs.mongodb.com/manual/reference/connection-string/ suggests to pass this along as URL's params. But this violates URL parser at readHostPortM in Database.MongoDB.Connection
Have you looked into this module: https://hackage.haskell.org/package/mongoDB-2.3.0.1/docs/Database-MongoDB-Transport-Tls.html
I'm not sure how persistent implements passing the connection information to mongodb driver.
Try using this module. I'll set up an account for Atlas and will take a look.
@marzhaev Did it work for you?
I'm trying to resolve the issue. I've managed to use Database.MongoDB.Transport.Tls but I'm running into the following error:
*** Exception: PersistMarshalError "User: could not find _id field: for doc: [ ok: 0, errmsg: \"user is not allowed to do action [find] on [test.user]\", code: 8000, codeName: \"AtlasError\"]"
This user does have permission from my understanding, I can 'insert' a record using the mongo console successfully.
Hmm I'm guessing as it's not specifying the AuthSource anywhere? How can this be set?
testAccess :: DB.Pipe -> Database -> Maybe MongoAuth -> IO ()
testAccess _ _ mAuth = do
pipe <- DBTLS.connect "cluster0-shard-00-00-gv0qj.mongodb.net" (PortNumber 27017)
x <- case mAuth of
Just (MongoAuth user pass) -> DB.access pipe DB.UnconfirmedWrites "admin" (DB.auth user pass)
Nothing -> error "no auth"
print x
return ()
I've narrowed it down to the above (the above seems to work). If I change the database
from admin
to test
it fails (x
becomes false)... (where admin is an existing database, and test is not).
A test
database is currently not present on the server. I assumed it would be created automatically (it did do this on a local mongo server).
Maybe something to do with the following line? Is this meant to be a hardcoded admin
vaule?
mongodb/Database/MongoDB/Transport/Tls.hs
Line 63 in 6431062
Okay! I've finally got this to work! You can only authenticate against the admin
table according to https://stackoverflow.com/questions/38237663/mongo-atlas-connection-authentication-failed-with-custom-databases.
So it seems the issue is somewhere in yesodweb/persistent
.
In the event it is useful to someone, this works for me:
actions :: ReaderT MongoContext IO ()
actions = do
i <- insert $ User "Dalalalala" $ Just 1234
lift $ print i
testAccess :: DB.Pipe -> Database -> Maybe MongoAuth -> IO ()
testAccess _ _ mAuth = do
pipe <- DBTLS.connect "cluster0-shard-00-00-gv0qj.mongodb.net" (PortNumber 27017)
x <- case mAuth of
Just (MongoAuth user pass) -> DB.access pipe DB.UnconfirmedWrites "admin" (DB.auth user pass)
Nothing -> error "no auth"
print x
DB.access pipe DB.UnconfirmedWrites "test" (actions)
return ()
@chrissound did you have any luck with writing to a shard? I am able to connect to an Atlas DB the same way you were, and I am able to read from it, but my writes aren't going through, although it is generating mongo ids for each document to be inserted.
I figured out why the writing wasn't working. I was hitting a secondary node rather than the primary one.