summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHari Khalsa <hkhalsa@10gen.com>2014-05-21 13:19:35 -0400
committerHari Khalsa <hkhalsa@10gen.com>2014-05-22 11:29:12 -0400
commit4829bf7cd9eb34db1de853a87c70c6752cc6e775 (patch)
tree9dd87cf1a70d6a91e86192f5f4d4cd326a6e5596
parent4e5ff6074e560b44134b803e957effd1315b3122 (diff)
downloadmongo-4829bf7cd9eb34db1de853a87c70c6752cc6e775.tar.gz
SERVER-13641 break up cloner.cpp into commands and functionality to make usage clearer
-rw-r--r--src/mongo/SConscript6
-rw-r--r--src/mongo/db/cloner.cpp318
-rw-r--r--src/mongo/db/commands/clone.cpp137
-rw-r--r--src/mongo/db/commands/clone_collection.cpp147
-rw-r--r--src/mongo/db/commands/copydb.cpp198
-rw-r--r--src/mongo/db/commands/copydb_getnonce.cpp133
-rw-r--r--src/mongo/db/commands/copydb_getnonce.h37
-rw-r--r--src/mongo/db/curop.h2
8 files changed, 656 insertions, 322 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index aaefb398725..66d0d77762a 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -643,6 +643,10 @@ serverOnlyFiles = [ "db/curop.cpp",
# most commands are only for mongod
"db/stats/top.cpp",
"db/commands/apply_ops.cpp",
+ "db/commands/clone_collection.cpp",
+ "db/commands/clone.cpp",
+ "db/commands/copydb.cpp",
+ "db/commands/copydb_getnonce.cpp",
"db/commands/compact.cpp",
"db/commands/auth_schema_upgrade_d.cpp",
"db/commands/create_indexes.cpp",
@@ -659,14 +663,12 @@ serverOnlyFiles = [ "db/curop.cpp",
"db/commands/find_and_modify.cpp",
"db/commands/group.cpp",
"db/commands/index_filter_commands.cpp",
- "db/commands/index_stats.cpp",
"db/commands/mr.cpp",
"db/commands/oplog_note.cpp",
"db/commands/pipeline_command.cpp",
"db/commands/parallel_collection_scan.cpp",
"db/commands/plan_cache_commands.cpp",
"db/commands/rename_collection.cpp",
- "db/commands/storage_details.cpp",
"db/commands/test_commands.cpp",
"db/commands/validate.cpp",
"db/pipeline/pipeline_d.cpp",
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp
index 8c0d075cc7d..99a7d31a766 100644
--- a/src/mongo/db/cloner.cpp
+++ b/src/mongo/db/cloner.cpp
@@ -545,322 +545,4 @@ namespace mongo {
errCode);
}
- /* Usage:
- mydb.$cmd.findOne( { clone: "fromhost" } );
- Note: doesn't work with authentication enabled, except as internal operation or for
- old-style users for backwards compatibility.
- */
- class CmdClone : public Command {
- public:
- virtual bool slaveOk() const {
- return false;
- }
- virtual bool isWriteCommandForConfigServer() const { return true; }
- virtual void help( stringstream &help ) const {
- help << "clone this database from an instance of the db on another host\n";
- help << "{ clone : \"host13\" }";
- }
- virtual Status checkAuthForCommand(ClientBasic* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- ActionSet actions;
- actions.addAction(ActionType::insert);
- actions.addAction(ActionType::createIndex);
- if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
- ResourcePattern::forDatabaseName(dbname), actions)) {
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
- }
- return Status::OK();
- }
- CmdClone() : Command("clone") { }
- virtual bool run(OperationContext* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- string from = cmdObj.getStringField("clone");
- if ( from.empty() )
- return false;
-
- CloneOptions opts;
- opts.fromDB = dbname;
- opts.logForRepl = ! fromRepl;
-
- // See if there's any collections we should ignore
- if( cmdObj["collsToIgnore"].type() == Array ){
- BSONObjIterator it( cmdObj["collsToIgnore"].Obj() );
-
- while( it.more() ){
- BSONElement e = it.next();
- if( e.type() == String ){
- opts.collsToIgnore.insert( e.String() );
- }
- }
- }
-
- set<string> clonedColls;
-
- Lock::DBWrite dbXLock(dbname);
- Client::Context context( dbname );
-
- Cloner cloner;
- bool rval = cloner.go(txn, context, from, opts, &clonedColls, errmsg);
-
- BSONArrayBuilder barr;
- barr.append( clonedColls );
-
- result.append( "clonedColls", barr.arr() );
-
- return rval;
-
- }
- } cmdClone;
-
- class CmdCloneCollection : public Command {
- public:
- virtual bool slaveOk() const {
- return false;
- }
- virtual bool isWriteCommandForConfigServer() const { return false; }
- CmdCloneCollection() : Command("cloneCollection") { }
-
- virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
- return parseNsFullyQualified(dbname, cmdObj);
- }
- virtual Status checkAuthForCommand(ClientBasic* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- std::string ns = parseNs(dbname, cmdObj);
-
- ActionSet actions;
- actions.addAction(ActionType::insert);
- actions.addAction(ActionType::createIndex); // SERVER-11418
-
- if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
- ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) {
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
- }
- return Status::OK();
- }
- virtual void help( stringstream &help ) const {
- help << "{ cloneCollection: <collection>, from: <host> [,query: <query_filter>] [,copyIndexes:<bool>] }"
- "\nCopies a collection from one server to another. Do not use on a single server as the destination "
- "is placed at the same db.collection (namespace) as the source.\n"
- ;
- }
- virtual bool run(OperationContext* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- string fromhost = cmdObj.getStringField("from");
- if ( fromhost.empty() ) {
- errmsg = "missing 'from' parameter";
- return false;
- }
- {
- HostAndPort h(fromhost);
- if( h.isSelf() ) {
- errmsg = "can't cloneCollection from self";
- return false;
- }
- }
- string collection = parseNs(dbname, cmdObj);
- if ( collection.empty() ) {
- errmsg = "bad 'cloneCollection' value";
- return false;
- }
- BSONObj query = cmdObj.getObjectField("query");
- if ( query.isEmpty() )
- query = BSONObj();
-
- BSONElement copyIndexesSpec = cmdObj.getField("copyindexes");
- bool copyIndexes = copyIndexesSpec.isBoolean() ? copyIndexesSpec.boolean() : true;
-
- log() << "cloneCollection. db:" << dbname << " collection:" << collection << " from: " << fromhost
- << " query: " << query << " " << ( copyIndexes ? "" : ", not copying indexes" ) << endl;
-
- Cloner cloner;
- auto_ptr<DBClientConnection> myconn;
- myconn.reset( new DBClientConnection() );
- if ( ! myconn->connect( fromhost , errmsg ) )
- return false;
-
- cloner.setConnection( myconn.release() );
-
- return cloner.copyCollection(txn, collection, query, errmsg, true, false, copyIndexes);
- }
- } cmdCloneCollection;
-
-
- // SERVER-4328 todo review for concurrency
- thread_specific_ptr< DBClientBase > authConn_;
- /* Usage:
- * admindb.$cmd.findOne( { copydbgetnonce: 1, fromhost: <connection string> } );
- *
- * Run against the mongod that is the intended target for the "copydb" command. Used to get a
- * nonce from the source of a "copydb" operation for authentication purposes. See the
- * description of the "copydb" command below.
- */
- class CmdCopyDbGetNonce : public Command {
- public:
- CmdCopyDbGetNonce() : Command("copydbgetnonce") { }
- virtual bool adminOnly() const {
- return true;
- }
- virtual bool slaveOk() const {
- return false;
- }
- virtual bool isWriteCommandForConfigServer() const { return false; }
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {} // No auth required
- virtual void help( stringstream &help ) const {
- help << "get a nonce for subsequent copy db request from secure server\n";
- help << "usage: {copydbgetnonce: 1, fromhost: <hostname>}";
- }
- virtual bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- string fromhost = cmdObj.getStringField("fromhost");
- if ( fromhost.empty() ) {
- /* copy from self */
- stringstream ss;
- ss << "localhost:" << serverGlobalParams.port;
- fromhost = ss.str();
- }
- BSONObj ret;
- ConnectionString cs = ConnectionString::parse(fromhost, errmsg);
- if (!cs.isValid()) {
- return false;
- }
- authConn_.reset(cs.connect(errmsg));
- if (!authConn_.get()) {
- return false;
- }
- if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) {
- errmsg = "couldn't get nonce " + ret.toString();
- return false;
- }
- result.appendElements( ret );
- return true;
- }
- } cmdCopyDBGetNonce;
-
- /* Usage:
- * admindb.$cmd.findOne( { copydb: 1, fromhost: <connection string>, fromdb: <db>,
- * todb: <db>[, username: <username>, nonce: <nonce>, key: <key>] } );
- *
- * The "copydb" command is used to copy a database. Note that this is a very broad definition.
- * This means that the "copydb" command can be used in the following ways:
- *
- * 1. To copy a database within a single node
- * 2. To copy a database within a sharded cluster, possibly to another shard
- * 3. To copy a database from one cluster to another
- *
- * Note that in all cases both the target and source database must be unsharded.
- *
- * The "copydb" command gets sent by the client or the mongos to the destination of the copy
- * operation. The node, cluster, or shard that recieves the "copydb" command must then query
- * the source of the database to be copied for all the contents and metadata of the database.
- *
- *
- *
- * When used with auth, there are two different considerations.
- *
- * The first is authentication with the target. The only entity that needs to authenticate with
- * the target node is the client, so authentication works there the same as it would with any
- * other command.
- *
- * The second is the authentication of the target with the source, which is needed because the
- * target must query the source directly for the contents of the database. To do this, the
- * client must use the "copydbgetnonce" command, in which the target will get a nonce from the
- * source and send it back to the client. The client can then hash its password with the nonce,
- * send it to the target when it runs the "copydb" command, which can then use that information
- * to authenticate with the source.
- *
- * NOTE: mongos doesn't know how to call or handle the "copydbgetnonce" command. See
- * SERVER-6427.
- *
- * NOTE: Since internal cluster auth works differently, "copydb" currently doesn't work between
- * shards in a cluster when auth is enabled. See SERVER-13080.
- */
- class CmdCopyDb : public Command {
- public:
- CmdCopyDb() : Command("copydb") { }
- virtual bool adminOnly() const {
- return true;
- }
- virtual bool slaveOk() const {
- return false;
- }
- virtual bool isWriteCommandForConfigServer() const { return false; }
- virtual Status checkAuthForCommand(ClientBasic* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj);
- }
- virtual void help( stringstream &help ) const {
- help << "copy a database from another host to this host\n";
- help << "usage: {copydb: 1, fromhost: <connection string>, fromdb: <db>, todb: <db>"
- << "[, slaveOk: <bool>, username: <username>, nonce: <nonce>, key: <key>]}";
- }
- virtual bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- string fromhost = cmdObj.getStringField("fromhost");
- bool fromSelf = fromhost.empty();
- if ( fromSelf ) {
- /* copy from self */
- stringstream ss;
- ss << "localhost:" << serverGlobalParams.port;
- fromhost = ss.str();
- }
-
- CloneOptions cloneOptions;
- cloneOptions.fromDB = cmdObj.getStringField("fromdb");
- cloneOptions.logForRepl = !fromRepl;
- cloneOptions.slaveOk = cmdObj["slaveOk"].trueValue();
- cloneOptions.useReplAuth = false;
- cloneOptions.snapshot = true;
- cloneOptions.mayYield = true;
- cloneOptions.mayBeInterrupted = false;
-
- string todb = cmdObj.getStringField("todb");
- if ( fromhost.empty() || todb.empty() || cloneOptions.fromDB.empty() ) {
- errmsg = "parms missing - {copydb: 1, fromhost: <connection string>, "
- "fromdb: <db>, todb: <db>}";
- return false;
- }
-
- // SERVER-4328 todo lock just the two db's not everything for the fromself case
- scoped_ptr<Lock::ScopedLock> lk( fromSelf ?
- static_cast<Lock::ScopedLock*>( new Lock::GlobalWrite() ) :
- static_cast<Lock::ScopedLock*>( new Lock::DBWrite( todb ) ) );
-
-
- Cloner cloner;
- string username = cmdObj.getStringField( "username" );
- string nonce = cmdObj.getStringField( "nonce" );
- string key = cmdObj.getStringField( "key" );
- if ( !username.empty() && !nonce.empty() && !key.empty() ) {
- uassert( 13008, "must call copydbgetnonce first", authConn_.get() );
- BSONObj ret;
- {
- dbtemprelease t;
- if ( !authConn_->runCommand( cloneOptions.fromDB,
- BSON( "authenticate" << 1 << "user" << username
- << "nonce" << nonce << "key" << key ), ret ) ) {
- errmsg = "unable to login " + ret.toString();
- return false;
- }
- }
- cloner.setConnection( authConn_.release() );
- }
- else if (!fromSelf) {
- // If fromSelf leave the cloner's conn empty, it will use a DBDirectClient instead.
-
- ConnectionString cs = ConnectionString::parse(fromhost, errmsg);
- if (!cs.isValid()) {
- return false;
- }
- DBClientBase* conn = cs.connect(errmsg);
- if (!conn) {
- return false;
- }
- cloner.setConnection(conn);
- }
- Client::Context ctx(todb);
- return cloner.go(txn, ctx, fromhost, cloneOptions, NULL, errmsg );
- }
- } cmdCopyDB;
-
} // namespace mongo
diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp
new file mode 100644
index 00000000000..b75ee5ceb69
--- /dev/null
+++ b/src/mongo/db/commands/clone.cpp
@@ -0,0 +1,137 @@
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#include "mongo/pch.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/util/builder.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/catalog/collection.h"
+#include "mongo/db/cloner.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/copydb.h"
+#include "mongo/db/commands/rename_collection.h"
+#include "mongo/db/db.h"
+#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index_builder.h"
+#include "mongo/db/instance.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/kill_current_op.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/repl/oplog.h"
+#include "mongo/db/repl/oplogreader.h"
+#include "mongo/db/pdfile.h"
+#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage_options.h"
+
+namespace mongo {
+
+ /* Usage:
+ mydb.$cmd.findOne( { clone: "fromhost" } );
+ Note: doesn't work with authentication enabled, except as internal operation or for
+ old-style users for backwards compatibility.
+ */
+ class CmdClone : public Command {
+ public:
+ CmdClone() : Command("clone") { }
+
+ virtual bool slaveOk() const {
+ return false;
+ }
+
+ virtual bool isWriteCommandForConfigServer() const { return true; }
+
+ virtual void help( stringstream &help ) const {
+ help << "clone this database from an instance of the db on another host\n";
+ help << "{ clone : \"host13\" }";
+ }
+
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ ActionSet actions;
+ actions.addAction(ActionType::insert);
+ actions.addAction(ActionType::createIndex);
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(dbname), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ return Status::OK();
+ }
+
+ virtual bool run(OperationContext* txn,
+ const string& dbname,
+ BSONObj& cmdObj,
+ int,
+ string& errmsg,
+ BSONObjBuilder& result,
+ bool fromRepl) {
+
+ string from = cmdObj.getStringField("clone");
+ if ( from.empty() )
+ return false;
+
+ CloneOptions opts;
+ opts.fromDB = dbname;
+ opts.logForRepl = ! fromRepl;
+
+ // See if there's any collections we should ignore
+ if( cmdObj["collsToIgnore"].type() == Array ){
+ BSONObjIterator it( cmdObj["collsToIgnore"].Obj() );
+
+ while( it.more() ){
+ BSONElement e = it.next();
+ if( e.type() == String ){
+ opts.collsToIgnore.insert( e.String() );
+ }
+ }
+ }
+
+ set<string> clonedColls;
+
+ Lock::DBWrite dbXLock(dbname);
+ Client::Context context( dbname );
+
+ Cloner cloner;
+ bool rval = cloner.go(txn, context, from, opts, &clonedColls, errmsg);
+
+ BSONArrayBuilder barr;
+ barr.append( clonedColls );
+
+ result.append( "clonedColls", barr.arr() );
+
+ return rval;
+
+ }
+ } cmdClone;
+
+} // namespace mongo
diff --git a/src/mongo/db/commands/clone_collection.cpp b/src/mongo/db/commands/clone_collection.cpp
new file mode 100644
index 00000000000..c0a124adbe3
--- /dev/null
+++ b/src/mongo/db/commands/clone_collection.cpp
@@ -0,0 +1,147 @@
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#include "mongo/pch.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/util/builder.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/catalog/collection.h"
+#include "mongo/db/cloner.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/copydb.h"
+#include "mongo/db/commands/rename_collection.h"
+#include "mongo/db/db.h"
+#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index_builder.h"
+#include "mongo/db/instance.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/kill_current_op.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/repl/oplog.h"
+#include "mongo/db/repl/oplogreader.h"
+#include "mongo/db/pdfile.h"
+#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage_options.h"
+
+namespace mongo {
+
+ class CmdCloneCollection : public Command {
+ public:
+ CmdCloneCollection() : Command("cloneCollection") { }
+
+ virtual bool slaveOk() const {
+ return false;
+ }
+
+ virtual bool isWriteCommandForConfigServer() const {
+ return false;
+ }
+
+ virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
+ return parseNsFullyQualified(dbname, cmdObj);
+ }
+
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ std::string ns = parseNs(dbname, cmdObj);
+
+ ActionSet actions;
+ actions.addAction(ActionType::insert);
+ actions.addAction(ActionType::createIndex); // SERVER-11418
+
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ return Status::OK();
+ }
+
+ virtual void help( stringstream &help ) const {
+ help << "{ cloneCollection: <collection>, from: <host> [,query: <query_filter>] [,copyIndexes:<bool>] }"
+ "\nCopies a collection from one server to another. Do not use on a single server as the destination "
+ "is placed at the same db.collection (namespace) as the source.\n"
+ ;
+ }
+
+ virtual bool run(OperationContext* txn,
+ const string& dbname,
+ BSONObj& cmdObj,
+ int,
+ string& errmsg,
+ BSONObjBuilder& result,
+ bool fromRepl) {
+
+ string fromhost = cmdObj.getStringField("from");
+ if ( fromhost.empty() ) {
+ errmsg = "missing 'from' parameter";
+ return false;
+ }
+
+ {
+ HostAndPort h(fromhost);
+ if( h.isSelf() ) {
+ errmsg = "can't cloneCollection from self";
+ return false;
+ }
+ }
+
+ string collection = parseNs(dbname, cmdObj);
+ if ( collection.empty() ) {
+ errmsg = "bad 'cloneCollection' value";
+ return false;
+ }
+ BSONObj query = cmdObj.getObjectField("query");
+ if ( query.isEmpty() )
+ query = BSONObj();
+
+ BSONElement copyIndexesSpec = cmdObj.getField("copyindexes");
+ bool copyIndexes = copyIndexesSpec.isBoolean() ? copyIndexesSpec.boolean() : true;
+
+ log() << "cloneCollection. db:" << dbname << " collection:" << collection << " from: " << fromhost
+ << " query: " << query << " " << ( copyIndexes ? "" : ", not copying indexes" ) << endl;
+
+ Cloner cloner;
+ auto_ptr<DBClientConnection> myconn;
+ myconn.reset( new DBClientConnection() );
+ if ( ! myconn->connect( fromhost , errmsg ) )
+ return false;
+
+ cloner.setConnection( myconn.release() );
+
+ return cloner.copyCollection(txn, collection, query, errmsg, true, false, copyIndexes);
+ }
+
+ } cmdCloneCollection;
+
+} // namespace mongo
diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp
new file mode 100644
index 00000000000..0db7a7950bb
--- /dev/null
+++ b/src/mongo/db/commands/copydb.cpp
@@ -0,0 +1,198 @@
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#include "mongo/pch.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/util/builder.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/catalog/collection.h"
+#include "mongo/db/cloner.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/copydb.h"
+#include "mongo/db/commands/copydb_getnonce.h"
+#include "mongo/db/commands/rename_collection.h"
+#include "mongo/db/db.h"
+#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index_builder.h"
+#include "mongo/db/instance.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/kill_current_op.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/repl/oplog.h"
+#include "mongo/db/repl/oplogreader.h"
+#include "mongo/db/pdfile.h"
+#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage_options.h"
+
+namespace mongo {
+
+ /* Usage:
+ * admindb.$cmd.findOne( { copydb: 1, fromhost: <connection string>, fromdb: <db>,
+ * todb: <db>[, username: <username>, nonce: <nonce>, key: <key>] } );
+ *
+ * The "copydb" command is used to copy a database. Note that this is a very broad definition.
+ * This means that the "copydb" command can be used in the following ways:
+ *
+ * 1. To copy a database within a single node
+ * 2. To copy a database within a sharded cluster, possibly to another shard
+ * 3. To copy a database from one cluster to another
+ *
+ * Note that in all cases both the target and source database must be unsharded.
+ *
+ * The "copydb" command gets sent by the client or the mongos to the destination of the copy
+ * operation. The node, cluster, or shard that recieves the "copydb" command must then query
+ * the source of the database to be copied for all the contents and metadata of the database.
+ *
+ *
+ *
+ * When used with auth, there are two different considerations.
+ *
+ * The first is authentication with the target. The only entity that needs to authenticate with
+ * the target node is the client, so authentication works there the same as it would with any
+ * other command.
+ *
+ * The second is the authentication of the target with the source, which is needed because the
+ * target must query the source directly for the contents of the database. To do this, the
+ * client must use the "copydbgetnonce" command, in which the target will get a nonce from the
+ * source and send it back to the client. The client can then hash its password with the nonce,
+ * send it to the target when it runs the "copydb" command, which can then use that information
+ * to authenticate with the source.
+ *
+ * NOTE: mongos doesn't know how to call or handle the "copydbgetnonce" command. See
+ * SERVER-6427.
+ *
+ * NOTE: Since internal cluster auth works differently, "copydb" currently doesn't work between
+ * shards in a cluster when auth is enabled. See SERVER-13080.
+ */
+ class CmdCopyDb : public Command {
+ public:
+ CmdCopyDb() : Command("copydb") { }
+
+ virtual bool adminOnly() const {
+ return true;
+ }
+
+ virtual bool slaveOk() const {
+ return false;
+ }
+
+ virtual bool isWriteCommandForConfigServer() const { return false; }
+
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj);
+ }
+
+ virtual void help( stringstream &help ) const {
+ help << "copy a database from another host to this host\n";
+ help << "usage: {copydb: 1, fromhost: <connection string>, fromdb: <db>, todb: <db>"
+ << "[, slaveOk: <bool>, username: <username>, nonce: <nonce>, key: <key>]}";
+ }
+
+ virtual bool run(OperationContext* txn,
+ const string& dbname,
+ BSONObj& cmdObj,
+ int,
+ string& errmsg,
+ BSONObjBuilder& result,
+ bool fromRepl) {
+
+ string fromhost = cmdObj.getStringField("fromhost");
+ bool fromSelf = fromhost.empty();
+ if ( fromSelf ) {
+ /* copy from self */
+ stringstream ss;
+ ss << "localhost:" << serverGlobalParams.port;
+ fromhost = ss.str();
+ }
+
+ CloneOptions cloneOptions;
+ cloneOptions.fromDB = cmdObj.getStringField("fromdb");
+ cloneOptions.logForRepl = !fromRepl;
+ cloneOptions.slaveOk = cmdObj["slaveOk"].trueValue();
+ cloneOptions.useReplAuth = false;
+ cloneOptions.snapshot = true;
+ cloneOptions.mayYield = true;
+ cloneOptions.mayBeInterrupted = false;
+
+ string todb = cmdObj.getStringField("todb");
+ if ( fromhost.empty() || todb.empty() || cloneOptions.fromDB.empty() ) {
+ errmsg = "parms missing - {copydb: 1, fromhost: <connection string>, "
+ "fromdb: <db>, todb: <db>}";
+ return false;
+ }
+
+ // SERVER-4328 todo lock just the two db's not everything for the fromself case
+ scoped_ptr<Lock::ScopedLock> lk( fromSelf ?
+ static_cast<Lock::ScopedLock*>( new Lock::GlobalWrite() ) :
+ static_cast<Lock::ScopedLock*>( new Lock::DBWrite( todb ) ) );
+
+ Cloner cloner;
+ string username = cmdObj.getStringField( "username" );
+ string nonce = cmdObj.getStringField( "nonce" );
+ string key = cmdObj.getStringField( "key" );
+ if ( !username.empty() && !nonce.empty() && !key.empty() ) {
+ uassert( 13008, "must call copydbgetnonce first", authConn_.get() );
+ BSONObj ret;
+ {
+ dbtemprelease t;
+ if ( !authConn_->runCommand( cloneOptions.fromDB,
+ BSON( "authenticate" << 1 << "user" << username
+ << "nonce" << nonce << "key" << key ), ret ) ) {
+ errmsg = "unable to login " + ret.toString();
+ return false;
+ }
+ }
+ cloner.setConnection( authConn_.release() );
+ }
+ else if (!fromSelf) {
+ // If fromSelf leave the cloner's conn empty, it will use a DBDirectClient instead.
+
+ ConnectionString cs = ConnectionString::parse(fromhost, errmsg);
+ if (!cs.isValid()) {
+ return false;
+ }
+ DBClientBase* conn = cs.connect(errmsg);
+ if (!conn) {
+ return false;
+ }
+ cloner.setConnection(conn);
+ }
+ Client::Context ctx(todb);
+ return cloner.go(txn, ctx, fromhost, cloneOptions, NULL, errmsg );
+ }
+
+ } cmdCopyDB;
+
+} // namespace mongo
diff --git a/src/mongo/db/commands/copydb_getnonce.cpp b/src/mongo/db/commands/copydb_getnonce.cpp
new file mode 100644
index 00000000000..a3ea4e00fd9
--- /dev/null
+++ b/src/mongo/db/commands/copydb_getnonce.cpp
@@ -0,0 +1,133 @@
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#include "mongo/pch.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/util/builder.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/catalog/collection.h"
+#include "mongo/db/cloner.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/copydb.h"
+#include "mongo/db/commands/rename_collection.h"
+#include "mongo/db/db.h"
+#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index_builder.h"
+#include "mongo/db/instance.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/kill_current_op.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/repl/oplog.h"
+#include "mongo/db/repl/oplogreader.h"
+#include "mongo/db/pdfile.h"
+#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage_options.h"
+
+namespace mongo {
+
+ // SERVER-4328 todo review for concurrency
+ // :(
+ thread_specific_ptr<DBClientBase> authConn_;
+
+ /* Usage:
+ * admindb.$cmd.findOne( { copydbgetnonce: 1, fromhost: <connection string> } );
+ *
+ * Run against the mongod that is the intended target for the "copydb" command. Used to get a
+ * nonce from the source of a "copydb" operation for authentication purposes. See the
+ * description of the "copydb" command below.
+ */
+ class CmdCopyDbGetNonce : public Command {
+ public:
+ CmdCopyDbGetNonce() : Command("copydbgetnonce") { }
+
+ virtual bool adminOnly() const {
+ return true;
+ }
+
+ virtual bool slaveOk() const {
+ return false;
+ }
+
+ virtual bool isWriteCommandForConfigServer() const { return false; }
+
+ virtual void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out) {
+ // No auth required
+ }
+
+ virtual void help( stringstream &help ) const {
+ help << "get a nonce for subsequent copy db request from secure server\n";
+ help << "usage: {copydbgetnonce: 1, fromhost: <hostname>}";
+ }
+
+ virtual bool run(OperationContext* txn,
+ const string&,
+ BSONObj& cmdObj,
+ int,
+ string& errmsg,
+ BSONObjBuilder& result,
+ bool fromRepl) {
+
+ string fromhost = cmdObj.getStringField("fromhost");
+ if ( fromhost.empty() ) {
+ /* copy from self */
+ stringstream ss;
+ ss << "localhost:" << serverGlobalParams.port;
+ fromhost = ss.str();
+ }
+
+ BSONObj ret;
+
+ ConnectionString cs = ConnectionString::parse(fromhost, errmsg);
+ if (!cs.isValid()) {
+ return false;
+ }
+
+ authConn_.reset(cs.connect(errmsg));
+ if (!authConn_.get()) {
+ return false;
+ }
+
+ if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) {
+ errmsg = "couldn't get nonce " + ret.toString();
+ return false;
+ }
+
+ result.appendElements( ret );
+ return true;
+ }
+
+ } cmdCopyDBGetNonce;
+
+} // namespace mongo
diff --git a/src/mongo/db/commands/copydb_getnonce.h b/src/mongo/db/commands/copydb_getnonce.h
new file mode 100644
index 00000000000..315459e44df
--- /dev/null
+++ b/src/mongo/db/commands/copydb_getnonce.h
@@ -0,0 +1,37 @@
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#include <boost/thread/tss.hpp>
+
+#include "mongo/client/dbclientinterface.h"
+
+namespace mongo {
+
+ extern thread_specific_ptr<DBClientBase> authConn_;
+
+} // namespace mongo
diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h
index 4c561192f37..9459b482bca 100644
--- a/src/mongo/db/curop.h
+++ b/src/mongo/db/curop.h
@@ -31,8 +31,6 @@
#pragma once
-#include <vector>
-
#include "mongo/bson/util/atomic_int.h"
#include "mongo/db/client.h"
#include "mongo/db/structure/catalog/namespace.h"