Search code examples
mongodbreplicaset

How to run Compact command on sharded mongo over mongos localhost?


I am very new on Mongo.I have shards and 3 replica on each.and 3 config server. I am unable to run compact command it gives an error "not authorized on admin to execute command" .I connected mongo instances and change security-authorization "disable-enable" section in mongod.conf and tried create new user but it gives an error "not authorized on admin to execute command" again.

How to connect and run commands on instances over mongos?


Solution

  • Check the documentation:

    Sharded Cluster

    compact only applies to mongod instances. In a sharded environment, run compact on each shard separately as a maintenance operation.

    You cannot issue compact against a mongos instance.

    You can run this script from mongos. It connects to all mongod instances in a loop and runs compact

    const MONGO_PASSWROD = "secret";
    const user = "local_admin";
    const map = db.adminCommand("getShardMap").map;
    
    
    for (let rs of Object.keys(map)) {
       if (rs == "config") continue; // Running 'compact' of Config server is most likely useless
       let uri = map[rs].split("/");
       let connectionString = `mongodb://${user}:${MONGO_PASSWROD}@${uri[1]}/admin?replicaSet=${uri[0]}&authSource=admin`;
       let replicaSet = Mongo(connectionString).getDB("admin");
       for (let member of replicaSet.adminCommand({ replSetGetStatus: 1 }).members) {
          if (!replicaSet.hello().hosts.includes(member.name)) continue; // Used to skip ARBITER
          if (member.health != 1 || !Array("PRIMARY", "SECONDARY").includes(member.stateStr)) {
             print(`Member state of ${member.name} is '${member.stateStr}' - skip 'compact'`);
          } else {
             let connectionString = `mongodb://${user}:${MONGO_PASSWROD}@${member.name}/admin?authSource=admin`;
             let node = Mongo(connectionString).getDB("admin");
             print(`node.adminCommand({ compact: "<collection name>" }) on ${member.name}`);
             // maybe optionally run 'node.stepDown()' in order to minimize impact  
             node.adminCommand({ compact: "<collection name>" });
          }
       }
    }
    

    Regarding authentication and privileges:

    In a Sharded Cluster you have two types of users, see Users

    • The sharded cluster users are created and used when you connect via mongos
    • The shard local users are created and used directly on the shards.

    In order to run compact you need to connect directly to the shard, thus you must use the shard local administrative user. I guess this user is not created yet, see Create the shard-local user administrator

    The tutorial creates two users ("shard-local user administrator" and "shard-local cluster administrator"), I don't see any reason for this. Create just one local admin user:

    const admin = db.getSiblingDB("admin")
    admin.createUser({ user: "local_admin", pwd: "secret", roles: ["clusterAdmin", "userAdminAnyDatabase"] }) 
    

    You need to create this user on each (PRIMARY) shard! On the config server, the sharded cluster users and the shard local users are the same. Thus it is not required to create local user on config server, it would be redundant.

    Just another note in case you use ReplicaSet with ARBITER. The ARBITER does not store any data, this includes user account data. Due to this the compact is pointless on ARBITER. However, if you need to create local user on ARBITER for whatever reason then see cannot authenticate in mongodb arbiter