Search code examples
node.jsmongodbreplicationmongodb-replica-set

Alternative to `replSetGetConfig` in MongoDB 2.4.5 driver?


I'm working with an application running MongoDB 2.4.5, and currently an upgrade is out of the question.

I'm writing some automation scripts in node.js to initiate a replica set, but since I'm starting out with 3 identical, existing mongodb nodes I can't just use the replSetInitiate command with all 3 nodes - I need to init with one which I intend to be the primary, and then call replSetReconfig with the additional 2 to make them wipe and sync up.

The problem is, I would call the replSetGetConfig command to get a config object which I can manipulate and send back, but this command was only added in mongodb 3.0. So what are my alternatives? Is there an alternative command to replSetGetConfig? Is there any way I can generate the appropriate config object myself after replSetInitiate is done? Or should I just give up and run a mongo shell with rs.conf()?

This is what that code looks like right now, which does not work in said version:

return connectToMongoDB(host)
    .then((db) => {
        // Initial configuration contains only the intended primary
        var cfg = {
            _id : id,
            members : [{ _id: 0, host: host }]
        };
        return executeMongoCommand(db, { replSetInitiate : cfg })
            .then((res) => {
                // Passing on the db object so I don't have to reconnect
                return {
                    db: db
                };
            });
    })
    .then((data) => {
        // This would work in 3.0.0 and up to get the current RS config, but doesn't work at all in 2.4.5
        return executeMongoCommand(data.db, { replSetGetConfig: 1 })
            .then((res) => {
                // storing the config we got and passing it on with the db object to the next step
                data.cfg = data;
                return data;
            })
    })
    .then((data) => {
        otherNodes.forEach((val, idx) => {
            data.cfg.members.push({ _id: idx+1, host: val });
        });
        return executeMongoCommand(data.db, { replSetReconfig : data.cfg });
    })
    .catch(console.error);

And the returned error is no such cmd: replSetGetConfig

(As a side note, rs.conf() is supposed to be a wrapper for replSetGetConfig for somehow the wrapper is supported and the underlying function is not. Don't get it.)

UPDATE / ANSWER:

Based on @Stennie 's answer below I've implemented the following function to get this information for both sides of version 3.0.0:

function getRSconfig(db){
    return new Promise((resolve, reject) => {
        if(parseInt(mongoVersion, 10) < 3){
            db.db("local").collection("system.replset").findOne()
                .then((data) => {
                    resolve(data);
                }, (err) => {
                    reject(err);
                });
        }
        else {
            executeMongoCommand(db, { replSetGetConfig: 1 })
                .then((data) => {
                    resolve(data);
                }, (err) => {
                    reject(err);
                })
        }
    });
}

And using this one to get the current version:

function getMongoVersion(db){
    var adminDb = db.admin();
    adminDb.serverStatus(function(err, info) {
        mongoVersion = info.version;
    });
}

Solution

  • Prior to the replSetGetConfig command being introduced, drivers read the config directly from the local database: db.getSiblingDB("local").system.replset.findOne().

    You could read this config document as a fallback for servers older than MongoDB 3.0, which introduced replSetGetConfig as a proper command abstraction. For newer servers the command is the supported API to use.