rpc::UniqueReply MockRemoteDBServer::runCommand(InstanceID id, const OpMsgRequest& request) { checkIfUp(id); std::string cmdName = request.getCommandName().toString(); BSONObj reply; { scoped_spinlock lk(_lock); uassert(ErrorCodes::IllegalOperation, str::stream() << "no reply for command: " << cmdName, _cmdMap.count(cmdName)); reply = _cmdMap[cmdName]->next(); } if (_delayMilliSec > 0) { mongo::sleepmillis(_delayMilliSec); } checkIfUp(id); { scoped_spinlock lk(_lock); _cmdCount++; } // We need to construct a reply message - it will always be read through a view so it // doesn't matter whether we use OpMsgReplyBuilder or LegacyReplyBuilder auto message = rpc::OpMsgReplyBuilder{}.setCommandReply(reply).done(); auto replyView = stdx::make_unique<rpc::OpMsgReply>(&message); return rpc::UniqueReply(std::move(message), std::move(replyView)); }
BSONObj CommandHelpers::runCommandDirectly(OperationContext* opCtx, const OpMsgRequest& request) { auto command = globalCommandRegistry()->findCommand(request.getCommandName()); invariant(command); BSONObjBuilder out; try { bool ok = command->publicRun(opCtx, request, out); appendCommandStatus(out, ok); } catch (const StaleConfigException&) { // These exceptions are intended to be handled at a higher level. throw; } catch (const DBException& ex) { out.resetToEmpty(); appendCommandStatus(out, ex.toStatus()); } return out.obj(); }
Message opCommandRequestFromOpMsgRequest(const OpMsgRequest& request) { const auto commandName = request.getCommandName(); BufBuilder builder; builder.skip(mongo::MsgData::MsgDataHeaderSize); // Leave room for message header. builder.appendStr(request.getDatabase()); builder.appendStr(commandName); // OP_COMMAND is only used when communicating with 3.4 nodes and they serialize their metadata // fields differently. In addition to field-level differences, some generic arguments are pulled // out to a metadata object, separate from the body. We do all down-conversion here so that the // rest of the code only has to deal with the current format. BSONObjBuilder metadataBuilder; // Will be appended to the message after we finish the body. { BSONObjBuilder bodyBuilder(builder); for (auto elem : request.body) { const auto fieldName = elem.fieldNameStringData(); if (fieldName == "$configServerState") { metadataBuilder.appendAs(elem, "configsvr"); } else if (fieldName == "$readPreference") { BSONObjBuilder ssmBuilder(metadataBuilder.subobjStart("$ssm")); ssmBuilder.append(elem); ssmBuilder.append("$secondaryOk", uassertStatusOK(ReadPreferenceSetting::fromInnerBSON(elem)) .canRunOnSecondary()); } else if (fieldName == "$db") { // skip } else if (fieldGoesInMetadata(commandName, fieldName)) { metadataBuilder.append(elem); } else { bodyBuilder.append(elem); } } for (auto&& seq : request.sequences) { invariant(seq.name.find('.') == std::string::npos); // Only support top-level for now. dassert(!bodyBuilder.asTempObj().hasField(seq.name)); bodyBuilder.append(seq.name, seq.objs); } } metadataBuilder.obj().appendSelfToBufBuilder(builder); MsgData::View msg = builder.buf(); msg.setLen(builder.len()); msg.setOperation(dbCommand); return Message(builder.release()); }
BSONObj CommandHelpers::runCommandDirectly(OperationContext* opCtx, const OpMsgRequest& request) { auto command = globalCommandRegistry()->findCommand(request.getCommandName()); invariant(command); rpc::OpMsgReplyBuilder replyBuilder; std::unique_ptr<CommandInvocation> invocation; try { invocation = command->parse(opCtx, request); invocation->run(opCtx, &replyBuilder); auto body = replyBuilder.getBodyBuilder(); CommandHelpers::extractOrAppendOk(body); } catch (const StaleConfigException&) { // These exceptions are intended to be handled at a higher level. throw; } catch (const DBException& ex) { if (ex.code() == ErrorCodes::Unauthorized) { CommandHelpers::auditLogAuthEvent(opCtx, invocation.get(), request, ex.code()); } auto body = replyBuilder.getBodyBuilder(); body.resetToEmpty(); appendCommandStatusNoThrow(body, ex.toStatus()); } return replyBuilder.releaseBody(); }