summaryrefslogtreecommitdiff
path: root/src/mongo/client
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2020-08-20 13:00:50 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-20 18:12:14 +0000
commitd3064df927c97abd402ee5768ab57667ed6849c9 (patch)
treec246336371b545bdc5942dab73aef5c094d99bd4 /src/mongo/client
parent526230bafa6e5a49f5783507734fba93486c19ae (diff)
downloadmongo-d3064df927c97abd402ee5768ab57667ed6849c9.tar.gz
SERVER-49380 Add API params to mongo shell
Diffstat (limited to 'src/mongo/client')
-rw-r--r--src/mongo/client/SConscript2
-rw-r--r--src/mongo/client/client_api_version_parameters.idl56
-rw-r--r--src/mongo/client/connection_string.h19
-rw-r--r--src/mongo/client/connection_string_connect.cpp24
-rw-r--r--src/mongo/client/dbclient_base.cpp47
-rw-r--r--src/mongo/client/dbclient_base.h15
-rw-r--r--src/mongo/client/dbclient_connection.cpp6
-rw-r--r--src/mongo/client/dbclient_connection.h3
-rw-r--r--src/mongo/client/dbclient_rs.cpp6
-rw-r--r--src/mongo/client/dbclient_rs.h3
-rw-r--r--src/mongo/client/mongo_uri.h5
-rw-r--r--src/mongo/client/mongo_uri_connect.cpp7
12 files changed, 164 insertions, 29 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index bea8a3d755a..f6d531a737e 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -182,6 +182,7 @@ clientDriverEnv.Library(
'dbclient_base.cpp',
'dbclient_cursor.cpp',
'index_spec.cpp',
+ env.Idlc('client_api_version_parameters.idl')[0],
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/dbmessage',
@@ -196,6 +197,7 @@ clientDriverEnv.Library(
'connection_string',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/idl/idl_parser',
'$BUILD_DIR/mongo/util/net/ssl_manager',
],
)
diff --git a/src/mongo/client/client_api_version_parameters.idl b/src/mongo/client/client_api_version_parameters.idl
new file mode 100644
index 00000000000..26a89f01d56
--- /dev/null
+++ b/src/mongo/client/client_api_version_parameters.idl
@@ -0,0 +1,56 @@
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# 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
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# 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 Server Side 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.
+
+global:
+ cpp_namespace: "mongo"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+structs:
+
+ # Follow the MongoDB Drivers API for passing API Version parameters in clients. The drivers API
+ # is like MongoClient(uri, api={version: "1", strict: true, deprecationErrors: true}).
+
+ ClientAPIVersionParameters:
+ description: "Parser for Versioned API parameters passed to 'new Mongo()' in the mongo shell"
+ strict: true
+ fields:
+ version:
+ description: "The requested API version"
+ type: string
+ # The server requires the apiVersion parameter in commands, leave enforcement to the server.
+ optional: true
+ strict:
+ description: "Whether to restrict the connection to behaviors in the requested API version"
+ type: bool
+ optional: true
+ deprecationErrors:
+ description: "Whether to restrict the connection to non-deprecated behaviors in the
+ requested API version"
+ type: bool
+ optional: true
diff --git a/src/mongo/client/connection_string.h b/src/mongo/client/connection_string.h
index 493c916528f..67f62116d16 100644
--- a/src/mongo/client/connection_string.h
+++ b/src/mongo/client/connection_string.h
@@ -43,6 +43,7 @@
namespace mongo {
+class ClientAPIVersionParameters;
class DBClientBase;
class MongoURI;
@@ -121,10 +122,12 @@ public:
bool operator==(const ConnectionString& other) const;
bool operator!=(const ConnectionString& other) const;
- std::unique_ptr<DBClientBase> connect(StringData applicationName,
- std::string& errmsg,
- double socketTimeout = 0,
- const MongoURI* uri = nullptr) const;
+ std::unique_ptr<DBClientBase> connect(
+ StringData applicationName,
+ std::string& errmsg,
+ double socketTimeout = 0,
+ const MongoURI* uri = nullptr,
+ const ClientAPIVersionParameters* apiParameters = nullptr) const;
static StatusWith<ConnectionString> parse(const std::string& url);
@@ -147,9 +150,11 @@ public:
virtual ~ConnectionHook() {}
// Returns an alternative connection object for a string
- virtual std::unique_ptr<DBClientBase> connect(const ConnectionString& c,
- std::string& errmsg,
- double socketTimeout) = 0;
+ virtual std::unique_ptr<DBClientBase> connect(
+ const ConnectionString& c,
+ std::string& errmsg,
+ double socketTimeout,
+ const ClientAPIVersionParameters* apiParameters = nullptr) = 0;
};
static void setConnectionHook(ConnectionHook* hook) {
diff --git a/src/mongo/client/connection_string_connect.cpp b/src/mongo/client/connection_string_connect.cpp
index 498bf1db74d..735fc47d2af 100644
--- a/src/mongo/client/connection_string_connect.cpp
+++ b/src/mongo/client/connection_string_connect.cpp
@@ -46,10 +46,12 @@ namespace mongo {
Mutex ConnectionString::_connectHookMutex = MONGO_MAKE_LATCH();
ConnectionString::ConnectionHook* ConnectionString::_connectHook = nullptr;
-std::unique_ptr<DBClientBase> ConnectionString::connect(StringData applicationName,
- std::string& errmsg,
- double socketTimeout,
- const MongoURI* uri) const {
+std::unique_ptr<DBClientBase> ConnectionString::connect(
+ StringData applicationName,
+ std::string& errmsg,
+ double socketTimeout,
+ const MongoURI* uri,
+ const ClientAPIVersionParameters* apiParameters) const {
MongoURI newURI{};
if (uri) {
newURI = *uri;
@@ -58,7 +60,8 @@ std::unique_ptr<DBClientBase> ConnectionString::connect(StringData applicationNa
switch (_type) {
case MASTER: {
for (const auto& server : _servers) {
- auto c = std::make_unique<DBClientConnection>(true, 0, newURI);
+ auto c = std::make_unique<DBClientConnection>(
+ true, 0, newURI, DBClientConnection::HandshakeValidationHook(), apiParameters);
c->setSoTimeout(socketTimeout);
LOGV2_DEBUG(20109,
@@ -76,8 +79,12 @@ std::unique_ptr<DBClientBase> ConnectionString::connect(StringData applicationNa
}
case SET: {
- auto set = std::make_unique<DBClientReplicaSet>(
- _setName, _servers, applicationName, socketTimeout, std::move(newURI));
+ auto set = std::make_unique<DBClientReplicaSet>(_setName,
+ _servers,
+ applicationName,
+ socketTimeout,
+ std::move(newURI),
+ apiParameters);
if (!set->connect()) {
errmsg = "connect failed to replica set ";
errmsg += toString();
@@ -98,7 +105,8 @@ std::unique_ptr<DBClientBase> ConnectionString::connect(StringData applicationNa
_connectHook);
// Double-checked lock, since this will never be active during normal operation
- auto replacementConn = _connectHook->connect(*this, errmsg, socketTimeout);
+ auto replacementConn =
+ _connectHook->connect(*this, errmsg, socketTimeout, apiParameters);
LOGV2(20111,
"Replacing connection to {oldConnString} with {newConnString}",
diff --git a/src/mongo/client/dbclient_base.cpp b/src/mongo/client/dbclient_base.cpp
index 34408b9fddd..04748a525af 100644
--- a/src/mongo/client/dbclient_base.cpp
+++ b/src/mongo/client/dbclient_base.cpp
@@ -45,10 +45,12 @@
#include "mongo/bson/util/bson_extract.h"
#include "mongo/bson/util/builder.h"
#include "mongo/client/authenticate.h"
+#include "mongo/client/client_api_version_parameters_gen.h"
#include "mongo/client/constants.h"
#include "mongo/client/dbclient_cursor.h"
#include "mongo/config.h"
#include "mongo/db/commands.h"
+#include "mongo/db/initialize_api_parameters_gen.h"
#include "mongo/db/json.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/query/kill_cursors_gen.h"
@@ -194,6 +196,43 @@ DBClientBase* DBClientBase::runFireAndForgetCommand(OpMsgRequest request) {
return this;
}
+namespace {
+void appendAPIVersionParameters(BSONObjBuilder& bob,
+ const ClientAPIVersionParameters& apiParameters) {
+ if (!apiParameters.getVersion()) {
+ return;
+ }
+
+ bool hasVersion = false, hasStrict = false, hasDeprecationErrors = false;
+ BSONObjIterator i = bob.iterator();
+ while (i.more()) {
+ auto elem = i.next();
+ if (elem.fieldNameStringData() == APIParametersFromClient::kApiVersionFieldName) {
+ hasVersion = true;
+ } else if (elem.fieldNameStringData() == APIParametersFromClient::kApiStrictFieldName) {
+ hasStrict = true;
+ } else if (elem.fieldNameStringData() ==
+ APIParametersFromClient::kApiDeprecationErrorsFieldName) {
+ hasDeprecationErrors = true;
+ }
+ }
+
+ if (!hasVersion) {
+ bob.append(APIParametersFromClient::kApiVersionFieldName, *apiParameters.getVersion());
+ }
+
+ // Include apiStrict/apiDeprecationErrors if they are not boost::none.
+ if (!hasStrict && apiParameters.getStrict()) {
+ bob.append(APIParametersFromClient::kApiStrictFieldName, *apiParameters.getStrict());
+ }
+
+ if (!hasDeprecationErrors && apiParameters.getDeprecationErrors()) {
+ bob.append(APIParametersFromClient::kApiDeprecationErrorsFieldName,
+ *apiParameters.getDeprecationErrors());
+ }
+}
+} // namespace
+
std::pair<rpc::UniqueReply, DBClientBase*> DBClientBase::runCommandWithTarget(
OpMsgRequest request) {
// Make sure to reconnect if needed before building our request, since the request depends on
@@ -204,9 +243,13 @@ std::pair<rpc::UniqueReply, DBClientBase*> DBClientBase::runCommandWithTarget(
auto host = getServerAddress();
auto opCtx = haveClient() ? cc().getOperationContext() : nullptr;
- if (_metadataWriter) {
+
+ if (_metadataWriter || _apiParameters.getVersion()) {
BSONObjBuilder metadataBob(std::move(request.body));
- uassertStatusOK(_metadataWriter(opCtx, &metadataBob));
+ if (_metadataWriter) {
+ uassertStatusOK(_metadataWriter(opCtx, &metadataBob));
+ }
+ appendAPIVersionParameters(metadataBob, _apiParameters);
request.body = metadataBob.obj();
}
diff --git a/src/mongo/client/dbclient_base.h b/src/mongo/client/dbclient_base.h
index 92e4b8e245f..19bf9d2c417 100644
--- a/src/mongo/client/dbclient_base.h
+++ b/src/mongo/client/dbclient_base.h
@@ -34,6 +34,7 @@
#include "mongo/base/string_data.h"
#include "mongo/client/authenticate.h"
+#include "mongo/client/client_api_version_parameters_gen.h"
#include "mongo/client/connection_string.h"
#include "mongo/client/dbclient_cursor.h"
#include "mongo/client/index_spec.h"
@@ -109,11 +110,15 @@ class DBClientBase : public DBClientQueryInterface {
DBClientBase& operator=(const DBClientBase&) = delete;
public:
- DBClientBase()
+ DBClientBase(const ClientAPIVersionParameters* apiParameters = nullptr)
: _logLevel(logv2::LogSeverity::Log()),
_connectionId(ConnectionIdSequence.fetchAndAdd(1)),
_cachedAvailableOptions((enum QueryOptions)0),
- _haveCachedAvailableOptions(false) {}
+ _haveCachedAvailableOptions(false) {
+ if (apiParameters) {
+ _apiParameters = *apiParameters;
+ }
+ }
virtual ~DBClientBase() {}
@@ -770,6 +775,10 @@ public:
virtual const SSLConfiguration* getSSLConfiguration() = 0;
#endif
+ const ClientAPIVersionParameters& getApiParameters() const {
+ return _apiParameters;
+ }
+
protected:
/** if the result of a command is ok*/
bool isOk(const BSONObj&);
@@ -836,6 +845,8 @@ private:
// The operationTime associated with the last command handles by the client.
// TODO(SERVER-49791): Implement proper tracking of operationTime.
Timestamp _lastOperationTime;
+
+ ClientAPIVersionParameters _apiParameters;
}; // DBClientBase
BSONElement getErrField(const BSONObj& result);
diff --git a/src/mongo/client/dbclient_connection.cpp b/src/mongo/client/dbclient_connection.cpp
index 7ae8c5ca793..66714d742de 100644
--- a/src/mongo/client/dbclient_connection.cpp
+++ b/src/mongo/client/dbclient_connection.cpp
@@ -678,8 +678,10 @@ unsigned long long DBClientConnection::query(std::function<void(DBClientCursorBa
DBClientConnection::DBClientConnection(bool _autoReconnect,
double so_timeout,
MongoURI uri,
- const HandshakeValidationHook& hook)
- : autoReconnect(_autoReconnect),
+ const HandshakeValidationHook& hook,
+ const ClientAPIVersionParameters* apiParameters)
+ : DBClientBase(apiParameters),
+ autoReconnect(_autoReconnect),
_autoReconnectBackoff(Seconds(1), Seconds(2)),
_hook(hook),
_uri(std::move(uri)) {
diff --git a/src/mongo/client/dbclient_connection.h b/src/mongo/client/dbclient_connection.h
index db6c0c2a567..f5408f839be 100644
--- a/src/mongo/client/dbclient_connection.h
+++ b/src/mongo/client/dbclient_connection.h
@@ -95,7 +95,8 @@ public:
DBClientConnection(bool _autoReconnect = false,
double so_timeout = 0,
MongoURI uri = {},
- const HandshakeValidationHook& hook = HandshakeValidationHook());
+ const HandshakeValidationHook& hook = HandshakeValidationHook(),
+ const ClientAPIVersionParameters* apiParameters = nullptr);
virtual ~DBClientConnection() {
_numConnections.fetchAndAdd(-1);
diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp
index 0359251d9fa..b9871482aac 100644
--- a/src/mongo/client/dbclient_rs.cpp
+++ b/src/mongo/client/dbclient_rs.cpp
@@ -133,8 +133,10 @@ DBClientReplicaSet::DBClientReplicaSet(const string& name,
const vector<HostAndPort>& servers,
StringData applicationName,
double so_timeout,
- MongoURI uri)
- : _setName(name),
+ MongoURI uri,
+ const ClientAPIVersionParameters* apiParameters)
+ : DBClientBase(apiParameters),
+ _setName(name),
_applicationName(applicationName.toString()),
_so_timeout(so_timeout),
_uri(std::move(uri)) {
diff --git a/src/mongo/client/dbclient_rs.h b/src/mongo/client/dbclient_rs.h
index 4710a300c5d..e86cac71ae9 100644
--- a/src/mongo/client/dbclient_rs.h
+++ b/src/mongo/client/dbclient_rs.h
@@ -67,7 +67,8 @@ public:
const std::vector<HostAndPort>& servers,
StringData applicationName,
double so_timeout = 0,
- MongoURI uri = {});
+ MongoURI uri = {},
+ const ClientAPIVersionParameters* apiParameters = nullptr);
/**
* Returns false if no member of the set were reachable. This object
diff --git a/src/mongo/client/mongo_uri.h b/src/mongo/client/mongo_uri.h
index 3d155e1123c..26546ed7af5 100644
--- a/src/mongo/client/mongo_uri.h
+++ b/src/mongo/client/mongo_uri.h
@@ -46,6 +46,8 @@
namespace mongo {
+class ClientAPIVersionParameters;
+
/**
* Encode a string for embedding in a URI.
* Replaces reserved bytes with %xx sequences.
@@ -149,7 +151,8 @@ public:
DBClientBase* connect(StringData applicationName,
std::string& errmsg,
- boost::optional<double> socketTimeoutSecs = boost::none) const;
+ boost::optional<double> socketTimeoutSecs = boost::none,
+ const ClientAPIVersionParameters* apiParameters = nullptr) const;
const std::string& getUser() const {
return _user;
diff --git a/src/mongo/client/mongo_uri_connect.cpp b/src/mongo/client/mongo_uri_connect.cpp
index ae556d20aa9..34144bc0b66 100644
--- a/src/mongo/client/mongo_uri_connect.cpp
+++ b/src/mongo/client/mongo_uri_connect.cpp
@@ -39,7 +39,8 @@ namespace mongo {
DBClientBase* MongoURI::connect(StringData applicationName,
std::string& errmsg,
- boost::optional<double> socketTimeoutSecs) const {
+ boost::optional<double> socketTimeoutSecs,
+ const ClientAPIVersionParameters* apiParameters) const {
OptionsMap::const_iterator it = _options.find("socketTimeoutMS");
if (it != _options.end() && !socketTimeoutSecs) {
try {
@@ -50,8 +51,8 @@ DBClientBase* MongoURI::connect(StringData applicationName,
}
}
- auto ret = std::unique_ptr<DBClientBase>(
- _connectString.connect(applicationName, errmsg, socketTimeoutSecs.value_or(0.0), this));
+ auto ret = std::unique_ptr<DBClientBase>(_connectString.connect(
+ applicationName, errmsg, socketTimeoutSecs.value_or(0.0), this, apiParameters));
if (!ret) {
return nullptr;
}