diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2020-08-20 13:00:50 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-08-20 18:12:14 +0000 |
commit | d3064df927c97abd402ee5768ab57667ed6849c9 (patch) | |
tree | c246336371b545bdc5942dab73aef5c094d99bd4 /src/mongo/client | |
parent | 526230bafa6e5a49f5783507734fba93486c19ae (diff) | |
download | mongo-d3064df927c97abd402ee5768ab57667ed6849c9.tar.gz |
SERVER-49380 Add API params to mongo shell
Diffstat (limited to 'src/mongo/client')
-rw-r--r-- | src/mongo/client/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/client/client_api_version_parameters.idl | 56 | ||||
-rw-r--r-- | src/mongo/client/connection_string.h | 19 | ||||
-rw-r--r-- | src/mongo/client/connection_string_connect.cpp | 24 | ||||
-rw-r--r-- | src/mongo/client/dbclient_base.cpp | 47 | ||||
-rw-r--r-- | src/mongo/client/dbclient_base.h | 15 | ||||
-rw-r--r-- | src/mongo/client/dbclient_connection.cpp | 6 | ||||
-rw-r--r-- | src/mongo/client/dbclient_connection.h | 3 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.cpp | 6 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.h | 3 | ||||
-rw-r--r-- | src/mongo/client/mongo_uri.h | 5 | ||||
-rw-r--r-- | src/mongo/client/mongo_uri_connect.cpp | 7 |
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; } |