Skip to content

Commit

Permalink
SERVER-32291 Implement _configsvrCreateCollection command
Browse files Browse the repository at this point in the history
  • Loading branch information
renctan committed Feb 6, 2018
1 parent 2f8f2c8 commit 3a26a90
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 8 deletions.
14 changes: 14 additions & 0 deletions jstests/auth/lib/commands_lib.js
Expand Up @@ -2500,6 +2500,20 @@ var authCommandsLib = {
}
]
},
{
testname: "_configsvrCreateCollection",
command: {_configsvrCreateCollection: "test.user"},
skipSharded: true,
expectFail: true,
testcases: [
{
runOnDb: "admin",
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true
},
]
},
{
testname: "create_views",
command: {create: "view", viewOn: "collection", pipeline: [{$match: {}}]},
Expand Down
1 change: 1 addition & 0 deletions jstests/core/views/views_all_commands.js
Expand Up @@ -69,6 +69,7 @@
_configsvrCommitChunkMerge: {skip: isAnInternalCommand},
_configsvrCommitChunkMigration: {skip: isAnInternalCommand},
_configsvrCommitChunkSplit: {skip: isAnInternalCommand},
_configsvrCreateCollection: {skip: isAnInternalCommand},
_configsvrCreateDatabase: {skip: isAnInternalCommand},
_configsvrDropCollection: {skip: isAnInternalCommand},
_configsvrDropDatabase: {skip: isAnInternalCommand},
Expand Down
Expand Up @@ -142,6 +142,11 @@
setupFuncs.createDatabase,
cleanupFuncs.dropDatabase);

// We are using a different name from ns because it was already created in setupFuncs.
checkCommandConfigSvr({_configsvrCreateCollection: dbName + '.bar', options: {}},
setupFuncs.createDatabase,
cleanupFuncs.dropDatabase);

// shardCollection
checkCommandMongos(
{shardCollection: ns, key: {_id: 1}}, setupFuncs.enableSharding, cleanupFuncs.dropDatabase);
Expand Down
15 changes: 11 additions & 4 deletions src/mongo/db/commands.cpp
Expand Up @@ -264,11 +264,19 @@ bool CommandHelpers::isUserManagementCommand(const std::string& name) {
}

BSONObj CommandHelpers::filterCommandRequestForPassthrough(const BSONObj& cmdObj) {
BSONObjIterator cmdIter(cmdObj);
BSONObjBuilder bob;
for (auto elem : cmdObj) {
filterCommandRequestForPassthrough(&cmdIter, &bob);
return bob.obj();
}

void CommandHelpers::filterCommandRequestForPassthrough(BSONObjIterator* cmdIter,
BSONObjBuilder* requestBuilder) {
while (cmdIter->more()) {
auto elem = cmdIter->next();
const auto name = elem.fieldNameStringData();
if (name == "$readPreference") {
BSONObjBuilder(bob.subobjStart("$queryOptions")).append(elem);
BSONObjBuilder(requestBuilder->subobjStart("$queryOptions")).append(elem);
} else if (!isGenericArgument(name) || //
name == "$queryOptions" || //
name == "maxTimeMS" || //
Expand All @@ -278,10 +286,9 @@ BSONObj CommandHelpers::filterCommandRequestForPassthrough(const BSONObj& cmdObj
name == "txnNumber") {
// This is the whitelist of generic arguments that commands can be trusted to blindly
// forward to the shards.
bob.append(elem);
requestBuilder->append(elem);
}
}
return bob.obj();
}

void CommandHelpers::filterCommandReplyForPassthrough(const BSONObj& cmdObj,
Expand Down
4 changes: 3 additions & 1 deletion src/mongo/db/commands.h
Expand Up @@ -160,7 +160,8 @@ struct CommandHelpers {
* what they send to the shards.
*/
static BSONObj filterCommandRequestForPassthrough(const BSONObj& cmdObj);
static void filterCommandReplyForPassthrough(const BSONObj& reply, BSONObjBuilder* output);
static void filterCommandRequestForPassthrough(BSONObjIterator* cmdIter,
BSONObjBuilder* requestBuilder);

/**
* Rewrites reply into a format safe to blindly forward from shards to clients.
Expand All @@ -169,6 +170,7 @@ struct CommandHelpers {
* what they return from the shards.
*/
static BSONObj filterCommandReplyForPassthrough(const BSONObj& reply);
static void filterCommandReplyForPassthrough(const BSONObj& reply, BSONObjBuilder* output);

/**
* Returns true if this a request for the 'help' information associated with the command.
Expand Down
1 change: 1 addition & 0 deletions src/mongo/db/s/SConscript
Expand Up @@ -176,6 +176,7 @@ env.Library(
'config/configsvr_add_shard_to_zone_command.cpp',
'config/configsvr_commit_chunk_migration_command.cpp',
'config/configsvr_control_balancer_command.cpp',
'config/configsvr_create_collection_command.cpp',
'config/configsvr_create_database_command.cpp',
'config/configsvr_drop_collection_command.cpp',
'config/configsvr_drop_database_command.cpp',
Expand Down
122 changes: 122 additions & 0 deletions src/mongo/db/s/config/configsvr_create_collection_command.cpp
@@ -0,0 +1,122 @@
/**
* Copyright (C) 2018 MongoDB 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.
*/

#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding

#include "mongo/platform/basic.h"

#include <set>

#include "mongo/db/audit.h"
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/catalog/collection_options.h"
#include "mongo/db/commands.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/s/grid.h"
#include "mongo/s/request_types/create_collection_gen.h"
#include "mongo/util/log.h"

namespace mongo {

using std::shared_ptr;
using std::set;
using std::string;

namespace {

/**
* Internal sharding command run on config servers to create a new collection with unassigned shard
* key. Call with { _configsvrCreateCollection: <string collName>, <other create options ...> }
*/
class ConfigSvrCreateCollectionCommand : public BasicCommand {
public:
ConfigSvrCreateCollectionCommand() : BasicCommand("_configsvrCreateCollection") {}

AllowedOnSecondary secondaryAllowed() const override {
return AllowedOnSecondary::kNever;
}

bool adminOnly() const override {
return true;
}

bool supportsWriteConcern(const BSONObj& cmd) const override {
return true;
}

std::string help() const override {
return "Internal command, which is exported by the sharding config server. Do not call "
"directly. Create a collection.";
}

Status checkAuthForCommand(Client* client,
const std::string& dbname,
const BSONObj& cmdObj) const override {
if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource(
ResourcePattern::forClusterResource(), ActionType::internal)) {
return Status(ErrorCodes::Unauthorized, "Unauthorized");
}

return Status::OK();
}

bool run(OperationContext* opCtx,
const std::string& dbname,
const BSONObj& cmdObj,
BSONObjBuilder& result) override {

if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer) {
return CommandHelpers::appendCommandStatus(
result,
Status(ErrorCodes::IllegalOperation,
"_configsvrCreateCollection can only be run on config servers"));
}

uassert(ErrorCodes::InvalidOptions,
str::stream() << "createCollection must be called with majority writeConcern, got "
<< cmdObj,
opCtx->getWriteConcern().wMode == WriteConcernOptions::kMajority);

auto createCmd = ConfigsvrCreateCollection::parse(
IDLParserErrorContext("ConfigsvrCreateCollection"), cmdObj);

CollectionOptions options;
uassertStatusOK(options.parse(createCmd.getOptions()));

ShardingCatalogManager::get(opCtx)->createCollection(opCtx, createCmd.getNs(), options);

return true;
}

} configsvrCreateCollectionCmd;

} // namespace
} // namespace mongo
1 change: 1 addition & 0 deletions src/mongo/s/SConscript
Expand Up @@ -82,6 +82,7 @@ env.Library(
'shard_id.cpp',
'versioning.cpp',
env.Idlc('database_version.idl')[0],
env.Idlc('request_types/create_collection.idl')[0],
env.Idlc('request_types/create_database.idl')[0],
env.Idlc('request_types/flush_routing_table_cache_updates.idl')[0],
env.Idlc('request_types/move_primary.idl')[0],
Expand Down
26 changes: 23 additions & 3 deletions src/mongo/s/commands/commands_public.cpp
Expand Up @@ -61,6 +61,7 @@
#include "mongo/s/commands/cluster_explain.h"
#include "mongo/s/grid.h"
#include "mongo/s/query/store_possible_cursor.h"
#include "mongo/s/request_types/create_collection_gen.h"
#include "mongo/s/stale_exception.h"
#include "mongo/scripting/engine.h"
#include "mongo/util/log.h"
Expand Down Expand Up @@ -519,9 +520,28 @@ class CreateCmd : public PublicGridCommand {
BSONObjBuilder& result) override {
uassertStatusOK(createShardDatabase(opCtx, dbName));

const auto dbInfo =
uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, dbName));
return passthrough(opCtx, dbName, dbInfo.primaryId(), cmdObj, result);
BSONObjIterator cmdIter(cmdObj);
invariant(cmdIter.more());

const NamespaceString ns(dbName, cmdIter.next().str());

ConfigsvrCreateCollection configCreateCmd;
configCreateCmd.setNs(ns);

BSONObjBuilder optionsBuilder;
CommandHelpers::filterCommandRequestForPassthrough(&cmdIter, &optionsBuilder);
configCreateCmd.setOptions(optionsBuilder.obj());

auto response =
Grid::get(opCtx)->shardRegistry()->getConfigShard()->runCommandWithFixedRetryAttempts(
opCtx,
ReadPreferenceSetting{ReadPreference::PrimaryOnly},
"admin",
CommandHelpers::appendMajorityWriteConcern(configCreateCmd.toBSON()),
Shard::RetryPolicy::kIdempotent);

uassertStatusOK(Shard::CommandResponse::getEffectiveStatus(response));
return true;
}

} createCmd;
Expand Down
46 changes: 46 additions & 0 deletions src/mongo/s/request_types/create_collection.idl
@@ -0,0 +1,46 @@
# Copyright (C) 2018 MongoDB 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.

# createDatabase IDL File

global:
cpp_namespace: "mongo"

imports:
- "mongo/idl/basic_types.idl"

structs:
ConfigsvrCreateCollection:
description: "The internal createCollection command on the config server"
strict: false
fields:
_configsvrCreateCollection:
cpp_name: ns
type: namespacestring
description: "The namespace of the collection to be created."
options:
type: object
description: "collection creation options"

0 comments on commit 3a26a90

Please sign in to comment.