0

As I'm introducing authentication for my MongoDB instance in Docker, I ran into problems which are probably related to the way agenda.js tries to connect to MongoDB, as the connection string invokes successful logs for mongoose connecting to the DB, therefore I assume the string should be valid.

Everything worked until I changed the connection string to use authentication. I verified the users are properly created in the database and also tried variations of the connection string and deleting/installing node modules.

Following output I get upon running docker-compose up:

server    | /server/node_modules/agenda/node_modules/mongodb/lib/utils.js:133
server    |       throw err;
server    |       ^
server    | 
server    | MongoError: command createIndexes requires authentication
server    |     at Connection.<anonymous> (/server/node_modules/agenda/node_modules/mongodb/lib/core/connection/pool.js:466:61)
server    |     at Connection.emit (events.js:314:20)
server    |     at processMessage (/server/node_modules/agenda/node_modules/mongodb/lib/core/connection/connection.js:384:10)
server    |     at Socket.<anonymous> (/server/node_modules/agenda/node_modules/mongodb/lib/core/connection/connection.js:553:15)
server    |     at Socket.emit (events.js:314:20)
server    |     at addChunk (_stream_readable.js:297:12)
server    |     at readableAddChunk (_stream_readable.js:272:9)
server    |     at Socket.Readable.push (_stream_readable.js:213:10)
server    |     at TCP.onStreamRead (internal/stream_base_commons.js:188:23)
server    | Emitted 'error' event on Agenda instance at:
server    |     at /server/node_modules/agenda/lib/agenda/db-init.js:23:14
server    |     at /server/node_modules/agenda/node_modules/mongodb/lib/operations/execute_operation.js:76:14
server    |     at /server/node_modules/agenda/node_modules/mongodb/lib/operations/execute_operation.js:63:27
server    |     at ClientSession.endSession (/server/node_modules/agenda/node_modules/mongodb/lib/core/sessions.js:135:41)
server    |     at executeCallback (/server/node_modules/agenda/node_modules/mongodb/lib/operations/execute_operation.js:59:17)
server    |     at handleCallback (/server/node_modules/agenda/node_modules/mongodb/lib/utils.js:129:55)
server    |     at /server/node_modules/agenda/node_modules/mongodb/lib/operations/create_index.js:85:14
server    |     at handleCallback (/server/node_modules/agenda/node_modules/mongodb/lib/utils.js:129:55)
server    |     at /server/node_modules/agenda/node_modules/mongodb/lib/operations/command.js:113:23
server    |     at /server/node_modules/agenda/node_modules/mongodb/lib/core/connection/pool.js:420:18
server    |     at processTicksAndRejections (internal/process/task_queues.js:79:11) {
server    |   ok: 0,
server    |   errmsg: 'command createIndexes requires authentication',
server    |   code: 13,
server    |   codeName: 'Unauthorized',
server    |   [Symbol(mongoErrorContextSymbol)]: {}
server    | }

package.json

"dependencies": {
    "agenda": "^4.1.2",
    "axios": "^0.21.1",
    "bcryptjs": "^2.4.3",
    "body-parser": "latest",
    "express": "^4.17.1",
    "infinite-timeout": "^0.1.0",
    "jsonwebtoken": "^8.5.1",
    "method-override": "^3.0.0",
    "mongoose": "^5.12.4",
    "mosca": "^2.8.3",
    "passport": "^0.4.1",
    "passport-jwt": "^4.0.0",
    "websocket": "^1.0.34",
    "webstorm": "^1.0.0",
    "ws": "latest"
  },
  "devDependencies": {
    "@shelf/jest-mongodb": "^1.1.3",
    "@types/express": "^4.17.1",
    "cors": "^2.8.5",
    "jest": "^24.9.0"
  },
  "engines": {
    "node": "12.x"
  }

docker-compose.yml

version: "3.8"
services:
  server:
    container_name: server
    build: .
    restart: unless-stopped
    ports:
      - "9000:9000"
      - "1883:1883"
    links:
      - mongo
    networks:
      - app-network
    command: npm start
  mongo:
    container_name: mongo
    image: mongo:4.4.4
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=superSafePassword
    ports:
      - "27317:27017"
    volumes:
      - dbdata:/data/db
      - "./init.js/:/docker-entrypoint-initdb.d/init.js:ro"
    restart: unless-stopped
    networks:
      - app-network
    command: mongod
networks:
  app-network:
    driver: bridge
volumes:
  dbdata:
  node_modules:

Script to create users init.js

db = db.getSiblingDB("dbName");
db.createUser(
    {
        user: "dbUser",
        pwd: "dbPassword",
        roles: [
            {
                role: "readWrite",
                db: "dbName"
            }
        ]
    }
);

Connection string

// mongo refers to the docker container
    connectionString : 'mongodb://dbUser:dbPassword@mongo:27317/dbName',  

How I initialize agenda:

class mScheduler {

    constructor() {
        if(typeof mScheduler.instance === 'object')
            return mScheduler.instance;

        this.agenda = new Agenda({ db: {address: config.connectionString, collection: 'agendaJobs', options: { useNewUrlParser: true }}, processEvery: '2 seconds', maxConcurrency : MAX_CONC});
        process.on('SIGTERM', this.endJobs);
        process.on('SIGINT', this.endJobs);
        setImmediate(async ()=> await this.agenda.start());
        mScheduler.instance = this;
        return this;
    }

someOtherMethods()
}

module.exports = new mScheduler();
GoWithTheFlow
  • 252
  • 6
  • 16
  • When you enable authentication then you need to create at least one admin user (i.e. user with `userAdmin` or `userAdminAnyDatabase` role). Did you create this? – Wernfried Domscheit Apr 19 '21 at 09:07
  • @WernfriedDomscheit Thank you, yes, through the environment variables MONGO_INITDB_ROOT_USERNAME and PASSWORD, MongoDB creates the specified root user on initialization. In the admin db I can verify this entry: ` db.getUsers() [ { "_id" : "admin.root", "userId" : UUID("b87bc3b0-e0bc-4e6d-b060-2fc007639b30"), "user" : "root", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ], "mechanisms" : [ "SCRAM-SHA-1", "SCRAM-SHA-256" ] } ] ` – GoWithTheFlow Apr 20 '21 at 00:33

1 Answers1

0

try this

workaround these deprecation warnings with Mongoose provided options

const connectionOptions = {
  useNewUrlParser: true,
  useCreateIndex: true,
  useFindAndModify: false,
  useUnifiedTopology: true,
  autoIndex: false
};
this.agenda = new Agenda({ db: {address: config.connectionString, collection: 'agendaJobs', options: connectionOptions}, processEvery: '2 seconds', maxConcurrency : MAX_CONC});
GoWithTheFlow
  • 252
  • 6
  • 16
  • Thank you. The connection to mongoose seems to work fine and I'm using the options you pointed out: `module.exports = async ()=>{ await mongoose.connect(config.connectionString,{useNewUrlParser: true, useUnifiedTopology:true, useCreateIndex:true, useFindAndModify:false}) .then(()=>console.log('Connected to MongoDB')) .catch((err)=>console.log('Cannot connect to MongoDB', err)); };` I get the success log message, so that should work. I also tried adding the options to the agenda connection, but no change in the outcome. – GoWithTheFlow Apr 20 '21 at 00:47
  • @GoWithTheFlow what messages are you getting from the agenda connection? – Abeeb Ridwan Olumide Apr 20 '21 at 01:02
  • I can see the error is emitted from this line of the db-init.js file in the ageda node_module: `this._collection.createIndex(this._indices, { name: "findAndLockNextJobIndex" }, (error) => { if (error) { debug("index creation failed"); this.emit("error", error); } else { ... }` The errrormsg as described in the opening: "errmsg: 'command createIndexes requires authentication'" – GoWithTheFlow Apr 20 '21 at 01:22
  • add autoIndex: false, to the option, if you still get error messages, check out this pages: https://mongoosejs.com/docs/connections.html https://mongoosejs.com/docs/deprecations.html – Abeeb Ridwan Olumide Apr 20 '21 at 01:54
  • I added autoIndex, but seems I forgot rebuilding the docker image after adding the connection options. So now the error disappeared, thank you. I also suggested an edit to your answer so it reflects the usage of the options in the Agenda connection – GoWithTheFlow Apr 20 '21 at 02:54