diff options
author | Irina Yatsenko <irina.yatsenko@mongodb.com> | 2022-08-03 05:02:22 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-08-03 05:56:12 +0000 |
commit | a64e8b26f542b3e3b3fd3b97fb6f46e8a378b74c (patch) | |
tree | e5f70225212a141decd144dae38f4498210edd1b /src | |
parent | ccddad0fd0ce788c9926416c61e518fb0e34086b (diff) | |
download | mongo-a64e8b26f542b3e3b3fd3b97fb6f46e8a378b74c.tar.gz |
SERVER-57384 Remove serverStatus counters and logging for deleted opcodes
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/commands/get_last_error.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.h | 22 | ||||
-rw-r--r-- | src/mongo/rpc/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/rpc/check_allowed_op_query_cmd.cpp | 77 | ||||
-rw-r--r-- | src/mongo/rpc/check_allowed_op_query_cmd.h (renamed from src/mongo/rpc/warn_unsupported_wire_ops.h) | 24 | ||||
-rw-r--r-- | src/mongo/rpc/op_legacy_integration_test.cpp | 291 | ||||
-rw-r--r-- | src/mongo/rpc/unsupported_wire_ops.idl | 46 | ||||
-rw-r--r-- | src/mongo/rpc/warn_unsupported_wire_ops.cpp | 142 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_get_last_error_cmd.cpp | 3 | ||||
-rw-r--r-- | src/mongo/s/commands/strategy.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/service_entry_point_mongos.cpp | 15 |
13 files changed, 134 insertions, 529 deletions
diff --git a/src/mongo/db/commands/get_last_error.cpp b/src/mongo/db/commands/get_last_error.cpp index 770218f1faf..063ebd12636 100644 --- a/src/mongo/db/commands/get_last_error.cpp +++ b/src/mongo/db/commands/get_last_error.cpp @@ -32,7 +32,7 @@ #include "mongo/db/client.h" #include "mongo/db/commands.h" -#include "mongo/rpc/warn_unsupported_wire_ops.h" +#include "mongo/rpc/check_allowed_op_query_cmd.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand @@ -66,7 +66,6 @@ public: const BSONObj&, std::string&, BSONObjBuilder&) { - warnUnsupportedOp(*opCtx->getClient(), "getLastError"); uasserted(5739000, "getLastError command is not supported"); return false; } diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index e9a08fded83..a8b1f577776 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -91,6 +91,7 @@ #include "mongo/db/transaction_validation.h" #include "mongo/db/vector_clock.h" #include "mongo/logv2/log.h" +#include "mongo/rpc/check_allowed_op_query_cmd.h" #include "mongo/rpc/factory.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/rpc/message.h" @@ -101,7 +102,6 @@ #include "mongo/rpc/metadata/tracking_metadata.h" #include "mongo/rpc/op_msg.h" #include "mongo/rpc/reply_builder_interface.h" -#include "mongo/rpc/warn_unsupported_wire_ops.h" #include "mongo/s/shard_cannot_refresh_due_to_locks_held_exception.h" #include "mongo/s/would_change_owning_shard_exception.h" #include "mongo/transport/hello_metrics.h" @@ -2129,9 +2129,6 @@ struct QueryOpRunner : SynchronousOpRunner { using SynchronousOpRunner::SynchronousOpRunner; DbResponse runSync() override { invariant(!executionContext->nsString().isCommand()); - - globalOpCounters.gotQueryDeprecated(); - warnUnsupportedOp(executionContext->client(), networkOpToString(dbQuery)); return makeErrorResponseToUnsupportedOpQuery("OP_QUERY is no longer supported"); } }; @@ -2139,8 +2136,6 @@ struct QueryOpRunner : SynchronousOpRunner { struct GetMoreOpRunner : SynchronousOpRunner { using SynchronousOpRunner::SynchronousOpRunner; DbResponse runSync() override { - globalOpCounters.gotGetMoreDeprecated(); - warnUnsupportedOp(executionContext->client(), networkOpToString(dbGetMore)); return makeErrorResponseToUnsupportedOpQuery("OP_GET_MORE is no longer supported"); } }; @@ -2160,7 +2155,6 @@ struct FireAndForgetOpRunner : SynchronousOpRunner { struct KillCursorsOpRunner : FireAndForgetOpRunner { using FireAndForgetOpRunner::FireAndForgetOpRunner; void runAndForget() override { - globalOpCounters.gotKillCursorsDeprecated(); uasserted(5745703, "OP_KILL_CURSORS is no longer supported"); } }; @@ -2168,9 +2162,6 @@ struct KillCursorsOpRunner : FireAndForgetOpRunner { struct InsertOpRunner : FireAndForgetOpRunner { using FireAndForgetOpRunner::FireAndForgetOpRunner; void runAndForget() override { - auto insertOp = InsertOp::parseLegacy(executionContext->getMessage()); - const auto nDocs = insertOp.getDocuments().size(); - globalOpCounters.gotInsertsDeprecated(nDocs); uasserted(5745702, "OP_INSERT is no longer supported"); } }; @@ -2178,7 +2169,6 @@ struct InsertOpRunner : FireAndForgetOpRunner { struct UpdateOpRunner : FireAndForgetOpRunner { using FireAndForgetOpRunner::FireAndForgetOpRunner; void runAndForget() override { - globalOpCounters.gotUpdateDeprecated(); uasserted(5745701, "OP_UPDATE is no longer supported"); } }; @@ -2186,7 +2176,6 @@ struct UpdateOpRunner : FireAndForgetOpRunner { struct DeleteOpRunner : FireAndForgetOpRunner { using FireAndForgetOpRunner::FireAndForgetOpRunner; void runAndForget() override { - globalOpCounters.gotDeleteDeprecated(); uasserted(5745700, "OP_DELETE is no longer supported"); } }; @@ -2233,7 +2222,6 @@ std::unique_ptr<HandleRequest::OpRunner> HandleRequest::makeOpRunner() { } DbResponse FireAndForgetOpRunner::runSync() { - warnUnsupportedOp(executionContext->client(), networkOpToString(executionContext->op())); runAndForget(); return {}; } diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp index e354f51f634..fca895940da 100644 --- a/src/mongo/db/stats/counters.cpp +++ b/src/mongo/db/stats/counters.cpp @@ -58,12 +58,7 @@ void OpCounters::_checkWrap(CacheExclusive<AtomicWord<long long>> OpCounters::*c _getmore->store(0); _command->store(0); - _insertDeprecated->store(0); _queryDeprecated->store(0); - _updateDeprecated->store(0); - _deleteDeprecated->store(0); - _getmoreDeprecated->store(0); - _killcursorsDeprecated->store(0); _insertOnExistingDoc->store(0); _updateOnMissingDoc->store(0); @@ -83,23 +78,9 @@ BSONObj OpCounters::getObj() const { b.append("command", _command->loadRelaxed()); auto queryDep = _queryDeprecated->loadRelaxed(); - auto getmoreDep = _getmoreDeprecated->loadRelaxed(); - auto killcursorsDep = _killcursorsDeprecated->loadRelaxed(); - auto updateDep = _updateDeprecated->loadRelaxed(); - auto deleteDep = _deleteDeprecated->loadRelaxed(); - auto insertDep = _insertDeprecated->loadRelaxed(); - auto totalDep = queryDep + getmoreDep + killcursorsDep + updateDep + deleteDep + insertDep; - - if (totalDep > 0) { + if (queryDep > 0) { BSONObjBuilder d(b.subobjStart("deprecated")); - - d.append("total", totalDep); - d.append("insert", insertDep); d.append("query", queryDep); - d.append("update", updateDep); - d.append("delete", deleteDep); - d.append("getmore", getmoreDep); - d.append("killcursors", killcursorsDep); } // Append counters for constraint relaxations, only if they exist. diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h index 3c01c3eb626..0a6273e6fba 100644 --- a/src/mongo/db/stats/counters.h +++ b/src/mongo/db/stats/counters.h @@ -74,24 +74,9 @@ public: _checkWrap(&OpCounters::_command, 1); } - void gotInsertsDeprecated(int n) { - _checkWrap(&OpCounters::_insertDeprecated, n); - } void gotQueryDeprecated() { _checkWrap(&OpCounters::_queryDeprecated, 1); } - void gotUpdateDeprecated() { - _checkWrap(&OpCounters::_updateDeprecated, 1); - } - void gotDeleteDeprecated() { - _checkWrap(&OpCounters::_deleteDeprecated, 1); - } - void gotGetMoreDeprecated() { - _checkWrap(&OpCounters::_getmoreDeprecated, 1); - } - void gotKillCursorsDeprecated() { - _checkWrap(&OpCounters::_killcursorsDeprecated, 1); - } BSONObj getObj() const; @@ -165,13 +150,8 @@ private: CacheExclusive<AtomicWord<long long>> _deleteFromMissingNamespace; CacheExclusive<AtomicWord<long long>> _acceptableErrorInCommand; - // Counters for deprecated opcodes. - CacheExclusive<AtomicWord<long long>> _insertDeprecated; + // Counter for the deprecated OP_QUERY opcode. CacheExclusive<AtomicWord<long long>> _queryDeprecated; - CacheExclusive<AtomicWord<long long>> _updateDeprecated; - CacheExclusive<AtomicWord<long long>> _deleteDeprecated; - CacheExclusive<AtomicWord<long long>> _getmoreDeprecated; - CacheExclusive<AtomicWord<long long>> _killcursorsDeprecated; }; extern OpCounters globalOpCounters; diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript index dc6a90092cc..d301f7e4db0 100644 --- a/src/mongo/rpc/SConscript +++ b/src/mongo/rpc/SConscript @@ -53,6 +53,7 @@ protoEnv.Library( env.Library( target='rpc', source=[ + 'check_allowed_op_query_cmd.cpp', 'factory.cpp', 'legacy_reply.cpp', 'legacy_reply_builder.cpp', @@ -60,8 +61,6 @@ env.Library( 'object_check.cpp', 'object_check.idl', 'reply_builder_interface.cpp', - 'unsupported_wire_ops.idl', - 'warn_unsupported_wire_ops.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/base', diff --git a/src/mongo/rpc/check_allowed_op_query_cmd.cpp b/src/mongo/rpc/check_allowed_op_query_cmd.cpp new file mode 100644 index 00000000000..165240f57c3 --- /dev/null +++ b/src/mongo/rpc/check_allowed_op_query_cmd.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2021-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. + */ + + +#include "mongo/platform/basic.h" + +#include "mongo/db/stats/counters.h" +#include "mongo/rpc/check_allowed_op_query_cmd.h" + +#include <fmt/format.h> +#include <string> + +namespace mongo { + +using namespace fmt::literals; + +void checkAllowedOpQueryCommand(Client& client, StringData cmd) { + static constexpr std::array allowed{ + "hello"_sd, + "isMaster"_sd, + "ismaster"_sd, + }; + const bool isAllowed = (std::find(allowed.begin(), allowed.end(), cmd) != allowed.end()); + + // The deprecated commands below are still used by some old drivers. Eventually, they should go. + static constexpr std::array temporarilyAllowed{ + "_isSelf"_sd, + "authenticate"_sd, + "buildinfo"_sd, + "buildInfo"_sd, + "saslContinue"_sd, + "saslStart"_sd, + }; + const bool isTemporarilyAllowed = + (std::find(temporarilyAllowed.begin(), temporarilyAllowed.end(), cmd) != + temporarilyAllowed.end()); + + if (!isAllowed && !isTemporarilyAllowed) { + uasserted( + ErrorCodes::UnsupportedOpQueryCommand, + "Unsupported OP_QUERY command: {}. The client driver may require an upgrade. " + "For more details see https://dochub.mongodb.org/core/legacy-opcode-removal"_format( + cmd)); + } + + if (isTemporarilyAllowed) { + globalOpCounters.gotQueryDeprecated(); + } +} + +} // namespace mongo diff --git a/src/mongo/rpc/warn_unsupported_wire_ops.h b/src/mongo/rpc/check_allowed_op_query_cmd.h index 942cfb99587..d6b45f377d0 100644 --- a/src/mongo/rpc/warn_unsupported_wire_ops.h +++ b/src/mongo/rpc/check_allowed_op_query_cmd.h @@ -30,32 +30,8 @@ #pragma once #include "mongo/db/client.h" -#include "mongo/rpc/message.h" namespace mongo { - -/** - * Logs a warning message for use of a legacy opcode or getLastError command once per each unique - * client in 60 minutes-period by default. - * - The specific unsupported op code or command is given by 'op' parameter. - * - Each client is identified by remote IP if client metadata is not available. If client metadata - * is available, a client is identified by client metadata’s application name + driver name + - * driver version. - * - The log message includes the following information. - * - Either client IP and port if client metadata is not available, - * - Or client metadata if client metadata is available. - * - The warning period is defined by 'deprecatedWireOpsWarningPeriodInSeconds' setParameter. - * - The default value is 3600 seconds. - * - If this value is 0, every legacy op code or getLastError request is logged with a warning - * message. - */ -void warnUnsupportedOp(Client& client, StringData op); - -/** - * Callback that gets invoked when 'deprecatedWireOpsWarningPeriodInSeconds' setting is changed. - */ -Status onUpdateOfWireOpsWarningPeriod(const int&); - /** * Logs a warning message and throws if 'cmd' is not an allowed 'OP_QUERY' command. * diff --git a/src/mongo/rpc/op_legacy_integration_test.cpp b/src/mongo/rpc/op_legacy_integration_test.cpp index 02928dabd3e..953dc19195e 100644 --- a/src/mongo/rpc/op_legacy_integration_test.cpp +++ b/src/mongo/rpc/op_legacy_integration_test.cpp @@ -47,15 +47,6 @@ std::unique_ptr<DBClientBase> getIntegrationTestConnection() { return std::move(swConn.getValue()); } -long getOpCount(BSONObj serverStatus, const char* opName) { - return serverStatus["opcounters"][opName].Long(); -} - -long getUnsupportedOpCount(BSONObj serverStatus, const char* opName) { - auto unsupportedOpcounters = serverStatus["opcounters"]["deprecated"]; - return unsupportedOpcounters ? unsupportedOpcounters[opName].Long() : 0; -} - Message makeUnsupportedOpUpdateMessage(StringData ns, BSONObj query, BSONObj update, int flags) { return makeMessage(dbUpdate, [&](BufBuilder& b) { const int reservedFlags = 0; @@ -133,14 +124,23 @@ int64_t getValidCursorIdFromFindCmd(DBClientBase* conn, const char* collName) { return cursorId; } -TEST(OpLegacy, UnsupportedWriteOpsCounters) { +TEST(OpLegacy, GetLastError) { auto conn = getIntegrationTestConnection(); - const std::string ns = "testOpLegacy.UnsupportedWriteOpsCounters"; - // Cache the counters prior to running the unsupported requests. - auto serverStatusCmd = fromjson("{serverStatus: 1}"); - BSONObj serverStatusReplyPrior; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReplyPrior)); + static const auto getLastErrorCommand = fromjson(R"({"getlasterror": 1})"); + BSONObj replyObj; + conn->runCommand("admin", getLastErrorCommand, replyObj); + + // 'getLastError' command is no longer supported and will always fail. + auto status = getStatusFromCommandResult(replyObj); + ASSERT_NOT_OK(status) << replyObj; + const auto expectedCode = conn->isMongos() ? 5739001 : 5739000; + ASSERT_EQ(status.code(), expectedCode) << replyObj; +} + +TEST(OpLegacy, UnsupportedWriteOps) { + auto conn = getIntegrationTestConnection(); + const std::string ns = "testOpLegacy.UnsupportedWriteOps"; // Building parts for the unsupported requests. const BSONObj doc1 = fromjson("{a: 1}"); @@ -149,7 +149,7 @@ TEST(OpLegacy, UnsupportedWriteOpsCounters) { const BSONObj query = fromjson("{a: {$lt: 42}}"); const BSONObj update = fromjson("{$set: {b: 2}}"); - // Issue the requests. They are expected to fail but should still be counted. + // Issue the requests. They are expected to fail. Message ignore; auto opInsert = makeUnsupportedOpInsertMessage(ns, insert, 2, 0 /*continue on error*/); ASSERT_THROWS(conn->call(opInsert, ignore), ExceptionForCat<ErrorCategory::NetworkError>); @@ -159,22 +159,6 @@ TEST(OpLegacy, UnsupportedWriteOpsCounters) { auto opDelete = makeUnsupportedOpRemoveMessage(ns, query, 0 /*limit*/); ASSERT_THROWS(conn->call(opDelete, ignore), ExceptionForCat<ErrorCategory::NetworkError>); - - // Check the opcounters after running the unsupported operations. - BSONObj serverStatusReply; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReply)); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "insert") + 2, - getUnsupportedOpCount(serverStatusReply, "insert")); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "update") + 1, - getUnsupportedOpCount(serverStatusReply, "update")); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "delete") + 1, - getUnsupportedOpCount(serverStatusReply, "delete")); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "total") + 2 + 1 + 1, - getUnsupportedOpCount(serverStatusReply, "total")); } void assertFailure(const Message response, StringData expectedErr) { @@ -189,22 +173,17 @@ void assertFailure(const Message response, StringData expectedErr) { << responseBody; } -TEST(OpLegacy, UnsupportedReadOpsCounters) { +TEST(OpLegacy, UnsupportedReadOps) { auto conn = getIntegrationTestConnection(); - const std::string ns = "testOpLegacy.UnsupportedReadOpsCounters"; + const std::string ns = "testOpLegacy.UnsupportedReadOps"; BSONObj insert = fromjson(R"({ - insert: "UnsupportedReadOpsCounters", + insert: "UnsupportedReadOps", documents: [ {a: 1},{a: 2},{a: 3},{a: 4},{a: 5},{a: 6},{a: 7} ] })"); BSONObj ignoreResponse; ASSERT(conn->runCommand("testOpLegacy", insert, ignoreResponse)); - // Cache the counters prior to running the unsupported requests. - auto serverStatusCmd = fromjson("{serverStatus: 1}"); - BSONObj serverStatusReplyPrior; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReplyPrior)); - // Issue the unsupported requests. They all should fail one way or another. Message opQueryRequest = makeUnsupportedOpQueryMessage(ns, fromjson("{}"), @@ -216,190 +195,25 @@ TEST(OpLegacy, UnsupportedReadOpsCounters) { conn->call(opQueryRequest, opQueryReply); assertFailure(opQueryReply, "OP_QUERY is no longer supported"); - const int64_t cursorId = getValidCursorIdFromFindCmd(conn.get(), "UnsupportedReadOpsCounters"); + const int64_t cursorId = getValidCursorIdFromFindCmd(conn.get(), "UnsupportedReadOps"); - Message opGetMoreRequest = - makeUnsupportedOpGetMoreMessage(ns, cursorId, 2 /*nToReturn*/, 0 /*flags*/); + auto opGetMore = makeUnsupportedOpGetMoreMessage(ns, cursorId, 2 /*nToReturn*/, 0 /*flags*/); Message opGetMoreReply; - conn->call(opGetMoreRequest, opGetMoreReply); + conn->call(opGetMore, opGetMoreReply); assertFailure(opGetMoreReply, "OP_GET_MORE is no longer supported"); - Message opKillCursorsRequest = makeUnsupportedOpKillCursorsMessage(cursorId); + auto opKillCursors = makeUnsupportedOpKillCursorsMessage(cursorId); Message opKillCursorsReply; - ASSERT_THROWS(conn->call(opKillCursorsRequest, opKillCursorsReply), + ASSERT_THROWS(conn->call(opKillCursors, opKillCursorsReply), ExceptionForCat<ErrorCategory::NetworkError>); - - // Check the opcounters after running the unsupported operations. - BSONObj serverStatusReply; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReply)); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "query") + 1, - getUnsupportedOpCount(serverStatusReply, "query")); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "getmore") + 1, - getUnsupportedOpCount(serverStatusReply, "getmore")); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "killcursors") + 1, - getUnsupportedOpCount(serverStatusReply, "killcursors")); - - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "total") + 1 + 1 + 1, - getUnsupportedOpCount(serverStatusReply, "total")); -} - -// The dochub link for warning messages about the removed op codes. -static constexpr auto docLink = "https://dochub.mongodb.org/core/legacy-opcode-removal"; - -// Check whether the most recent "deprecation" entry in the log matches the given opName and -// severity (if the 'severity' string isn't empty). Return 'false' if no deprecation entries found. -bool wasLogged(DBClientBase* conn, const std::string& opName, const std::string& severity) { - BSONObj getLogResponse; - ASSERT(conn->runCommand("admin", fromjson("{getLog: 'global'}"), getLogResponse)); - - auto logEntries = getLogResponse["log"].Array(); - for (auto it = logEntries.rbegin(); it != logEntries.rend(); ++it) { - auto entry = it->String(); - if (entry.find("\"id\":5578800") != std::string::npos) { - ASSERT_TRUE(entry.find(docLink) != std::string::npos); - const bool severityMatches = severity.empty() || - (entry.find(std::string("\"s\":\"") + severity + "\"") != std::string::npos); - const bool opNameMatches = - (entry.find(std::string("\"op\":\"") + opName + "\"") != std::string::npos); - return severityMatches && opNameMatches; - } - } - return false; -} - -void getLastError(DBClientBase* conn) { - static const auto getLastErrorCommand = fromjson(R"({"getlasterror": 1})"); - BSONObj replyObj; - conn->runCommand("admin", getLastErrorCommand, replyObj); - - // getLastError command is no longer supported and must always fails. - auto status = getStatusFromCommandResult(replyObj); - ASSERT_NOT_OK(status) << replyObj; - const auto expectedCode = conn->isMongos() ? 5739001 : 5739000; - ASSERT_EQ(status.code(), expectedCode) << replyObj; -} - -void exerciseUnsupportedOps(DBClientBase* conn, const std::string& expectedSeverity) { - // Build the unsupported requests and the getLog command. - const std::string ns = "testOpLegacy.exerciseUnsupportedOps"; - - // Insert some docs into the collection so even though the legacy write ops are failing we can - // still test getMore, killCursors and query. - BSONObj data = fromjson(R"({ - insert: "exerciseUnsupportedOps", - documents: [ {a: 1},{a: 2},{a: 3},{a: 4},{a: 5},{a: 6},{a: 7} ] - })"); - BSONObj ignoreResponse; - ASSERT(conn->runCommand("testOpLegacy", data, ignoreResponse)); - - const BSONObj doc1 = fromjson("{a: 1}"); - const BSONObj doc2 = fromjson("{a: 2}"); - const BSONObj insert[2] = {doc1, doc2}; - const BSONObj query = fromjson("{a: {$lt: 42}}"); - const BSONObj update = fromjson("{$set: {b: 2}}"); - auto opInsert = makeUnsupportedOpInsertMessage(ns, insert, 2, 0 /*continue on error*/); - auto opUpdate = makeUnsupportedOpUpdateMessage(ns, query, update, 0 /*no upsert, no multi*/); - auto opDelete = makeUnsupportedOpRemoveMessage(ns, query, 0 /*limit*/); - auto opQuery = makeUnsupportedOpQueryMessage( - ns, query, 2 /*nToReturn*/, 0 /*nToSkip*/, nullptr /*fieldsToReturn*/, 0 /*queryOptions*/); - Message ignore; - - // The first unsupported call after adding a suppression is still logged with elevated severity - // and after it the suppression kicks in. Any unsupported op can be used to start the - // suppression period, here we chose getLastError. - getLastError(conn); - - ASSERT_THROWS(conn->call(opInsert, ignore), ExceptionForCat<ErrorCategory::NetworkError>); - ASSERT(wasLogged(conn, "insert", expectedSeverity)); - - getLastError(conn); - ASSERT(wasLogged(conn, "getLastError", expectedSeverity)); - - ASSERT_THROWS(conn->call(opUpdate, ignore), ExceptionForCat<ErrorCategory::NetworkError>); - ASSERT(wasLogged(conn, "update", expectedSeverity)); - - Message replyQuery; - conn->call(opQuery, replyQuery); - ASSERT(wasLogged(conn, "query", expectedSeverity)); - - int64_t cursorId = getValidCursorIdFromFindCmd(conn, "exerciseUnsupportedOps"); - - auto opGetMore = makeUnsupportedOpGetMoreMessage(ns, cursorId, 2 /*nToReturn*/, 0 /*flags*/); - Message replyGetMore; - conn->call(opGetMore, replyGetMore); - ASSERT(wasLogged(conn, "getmore", expectedSeverity)); - - auto opKillCursors = makeUnsupportedOpKillCursorsMessage(cursorId); - ASSERT_THROWS(conn->call(opKillCursors, ignore), ExceptionForCat<ErrorCategory::NetworkError>); - ASSERT(wasLogged(conn, "killcursors", expectedSeverity)); - - ASSERT_THROWS(conn->call(opDelete, ignore), ExceptionForCat<ErrorCategory::NetworkError>); - ASSERT(wasLogged(conn, "remove", expectedSeverity)); -} - -void setUnsupportedWireOpsWarningPeriod(DBClientBase* conn, Seconds timeout) { - const BSONObj warningTimeout = - BSON("setParameter" << 1 << "deprecatedWireOpsWarningPeriodInSeconds" << timeout.count()); - BSONObj response; - ASSERT(conn->runCommand("admin", warningTimeout, response)); -} - -class UnsupportedWireOpsWarningPeriodScope { -public: - UnsupportedWireOpsWarningPeriodScope() { - auto conn = getIntegrationTestConnection(); - BSONObj currentSetting; - ASSERT(conn->runCommand( - "admin", - fromjson("{getParameter: 1, deprecatedWireOpsWarningPeriodInSeconds: 1}"), - currentSetting)); - timeout = currentSetting["deprecatedWireOpsWarningPeriodInSeconds"].Int(); - } - ~UnsupportedWireOpsWarningPeriodScope() { - auto conn = getIntegrationTestConnection(); - setUnsupportedWireOpsWarningPeriod(conn.get(), Seconds{timeout}); - } - -private: - int timeout = 3600; -}; - -TEST(OpLegacy, UnsupportedOpsLogging) { - UnsupportedWireOpsWarningPeriodScope timeoutSettingScope; - - auto conn = getIntegrationTestConnection(); - - // This test relies on the fact that the suite is run at D2 logging level. - BSONObj logSettings; - ASSERT(conn->runCommand( - "admin", fromjson("{getParameter: 1, logComponentVerbosity: {command: 1}}"), logSettings)); - ASSERT_LTE(2, logSettings["logComponentVerbosity"]["command"]["verbosity"].Int()); - - setUnsupportedWireOpsWarningPeriod(conn.get(), Seconds{0} /*timeout*/); - exerciseUnsupportedOps(conn.get(), "W" /*expectedSeverity*/); - - setUnsupportedWireOpsWarningPeriod(conn.get(), Seconds{3600} /*timeout*/); - exerciseUnsupportedOps(conn.get(), "D2" /*expectedSeverity*/); } TEST(OpLegacy, GenericCommandViaOpQuery) { auto conn = getIntegrationTestConnection(); - auto serverStatusCmd = fromjson("{serverStatus: 1}"); - BSONObj serverStatusReplyPrior; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReplyPrior)); - - // Because we cannot link the log entries to the issued commands, limit the search window for - // the query-related entry in the log by first running a different command (e.g. getLastError). - getLastError(conn.get()); - ASSERT(wasLogged(conn.get(), "getLastError", "")); - // The actual command doesn't matter, as long as it's not 'hello' or 'isMaster'. auto opQuery = makeUnsupportedOpQueryMessage("testOpLegacy.$cmd", - serverStatusCmd, + fromjson("{serverStatus: 1}"), 1 /*nToReturn*/, 0 /*nToSkip*/, nullptr /*fieldsToReturn*/, @@ -411,36 +225,27 @@ TEST(OpLegacy, GenericCommandViaOpQuery) { BSONObj obj = data.read<BSONObj>(); auto status = getStatusFromCommandResult(obj); ASSERT_EQ(status.code(), ErrorCodes::UnsupportedOpQueryCommand); - - // The logic around log severity for the deprecation logging is tested elsewhere. Here we check - // that it gets logged at all. - ASSERT(wasLogged(conn.get(), "query", "")); - - BSONObj serverStatusReply; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReply)); - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "query") + 1, - getUnsupportedOpCount(serverStatusReply, "query")); } -// 'hello' and 'isMaster' commands, issued via OP_QUERY protocol, are still fully supported. -void testAllowedCommand(const char* command, ErrorCodes::Error code = ErrorCodes::OK) { +// Test commands that are still allowed via OP_QUERY protocol. +void testAllowedCommand(const char* command, + bool expectToBeCounted, + ErrorCodes::Error code = ErrorCodes::OK) { auto conn = getIntegrationTestConnection(); - auto serverStatusCmd = fromjson("{serverStatus: 1}"); - BSONObj serverStatusReplyPrior; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReplyPrior)); - - // Because we cannot link the log entries to the issued commands, limit the search window for - // the query-related entry in the log by first running a different command (e.g. getLastError). - getLastError(conn.get()); - ASSERT(wasLogged(conn.get(), "getLastError", "")); - auto opQuery = makeUnsupportedOpQueryMessage("testOpLegacy.$cmd", fromjson(command), 1 /*nToReturn*/, 0 /*nToSkip*/, nullptr /*fieldsToReturn*/, 0 /*queryOptions*/); + + auto serverStatusCmd = fromjson("{serverStatus: 1}"); + BSONObj serverStatus; + ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatus)); + auto opCountersPrior = serverStatus["opcounters"]["deprecated"]; + const auto queryCountPrior = opCountersPrior ? opCountersPrior["query"].Long() : 0; + Message replyQuery; conn->call(opQuery, replyQuery); QueryResult::ConstView qr = replyQuery.singleData().view2ptr(); @@ -449,36 +254,35 @@ void testAllowedCommand(const char* command, ErrorCodes::Error code = ErrorCodes auto status = getStatusFromCommandResult(obj); ASSERT_EQ(status.code(), code); - ASSERT_FALSE(wasLogged(conn.get(), "query", "")); + ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatus)); + auto opCounters = serverStatus["opcounters"]["deprecated"]; + const auto queryCount = opCounters ? opCounters["query"].Long() : 0; - BSONObj serverStatusReply; - ASSERT(conn->runCommand("admin", serverStatusCmd, serverStatusReply)); - ASSERT_EQ(getUnsupportedOpCount(serverStatusReplyPrior, "query"), - getUnsupportedOpCount(serverStatusReply, "query")); + ASSERT_EQ(queryCountPrior + (expectToBeCounted ? 1 : 0), queryCount) << command; } TEST(OpLegacy, IsSelfCommandViaOpQuery) { - testAllowedCommand("{_isSelf: 1}"); + testAllowedCommand("{_isSelf: 1}", true /* expectToBeCounted */); } TEST(OpLegacy, BuildinfoCommandViaOpQuery) { - testAllowedCommand("{buildinfo: 1}"); + testAllowedCommand("{buildinfo: 1}", true /* expectToBeCounted */); } TEST(OpLegacy, BuildInfoCommandViaOpQuery) { - testAllowedCommand("{buildInfo: 1}"); + testAllowedCommand("{buildInfo: 1}", true /* expectToBeCounted */); } TEST(OpLegacy, HelloCommandViaOpQuery) { - testAllowedCommand("{hello: 1}"); + testAllowedCommand("{hello: 1}", false /* expectToBeCounted */); } TEST(OpLegacy, IsMasterCommandViaOpQuery) { - testAllowedCommand("{isMaster: 1}"); + testAllowedCommand("{isMaster: 1}", false /* expectToBeCounted */); } TEST(OpLegacy, IsmasterCommandViaOpQuery) { - testAllowedCommand("{ismaster: 1}"); + testAllowedCommand("{ismaster: 1}", false /* expectToBeCounted */); } TEST(OpLegacy, SaslStartCommandViaOpQuery) { @@ -500,6 +304,7 @@ TEST(OpLegacy, SaslStartCommandViaOpQuery) { } } })", + true /* expectToBeCounted */, ErrorCodes::AuthenticationFailed); } @@ -521,6 +326,7 @@ TEST(OpLegacy, SaslContinueCommandViaOpQuery) { }, "conversationId":1 })", + true /* expectToBeCounted */, ErrorCodes::ProtocolError); } @@ -533,6 +339,7 @@ TEST(OpLegacy, AuthenticateCommandViaOpQuery) { // an invalid authentication request. The AuthenticationFailed error code means that it passes // request parsing. testAllowedCommand(R"({authenticate: 1, mechanism: "MONGODB-X509"})", + true /* expectToBeCounted */, ErrorCodes::AuthenticationFailed); } diff --git a/src/mongo/rpc/unsupported_wire_ops.idl b/src/mongo/rpc/unsupported_wire_ops.idl deleted file mode 100644 index 800b902c2cf..00000000000 --- a/src/mongo/rpc/unsupported_wire_ops.idl +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2021-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 - cpp_includes: - - "mongo/rpc/warn_unsupported_wire_ops.h" - -server_parameters: - deprecatedWireOpsWarningPeriodInSeconds: - description: "The period in which the server logs a warning message for use of removed op - codes and getLastError command. The server logs a warning message only once per each client - in this period irrespective of how many such requests have been received. Such requests - include OP_QUERY, OP_GET_MORE, OP_KILL_CURSORS, OP_INSERT, OP_UPDATE, OP_DELETE op codes and - getLastError command." - set_at: [ startup, runtime ] - cpp_vartype: AtomicWord<int> - on_update: "onUpdateOfWireOpsWarningPeriod" - cpp_varname: deprecatedWireOpsWarningPeriodInSeconds - default: 3600 - validator: - gte: 0 diff --git a/src/mongo/rpc/warn_unsupported_wire_ops.cpp b/src/mongo/rpc/warn_unsupported_wire_ops.cpp deleted file mode 100644 index 11a2f9f6699..00000000000 --- a/src/mongo/rpc/warn_unsupported_wire_ops.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (C) 2021-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. - */ - - -#include "mongo/platform/basic.h" - -#include "mongo/rpc/warn_unsupported_wire_ops.h" - -#include <fmt/format.h> -#include <string> - -#include "mongo/db/client.h" -#include "mongo/db/stats/counters.h" -#include "mongo/logv2/log.h" -#include "mongo/logv2/log_severity_suppressor.h" -#include "mongo/rpc/metadata/client_metadata.h" -#include "mongo/rpc/unsupported_wire_ops_gen.h" -#include "mongo/util/duration.h" -#include "mongo/util/static_immortal.h" -#include "mongo/util/synchronized_value.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand - - -namespace mongo { - -using namespace fmt::literals; - -namespace { - -class SeveritySource { -public: - logv2::LogSeverity get(const std::string& key) { - return (***(_supressor))(key); - } - - void refresh() { - *(_supressor) = _makeSuppressor(); - } - -private: - using Suppressor = logv2::KeyedSeveritySuppressor<std::string>; - - static std::unique_ptr<Suppressor> _makeSuppressor() { - return std::make_unique<Suppressor>(Seconds{deprecatedWireOpsWarningPeriodInSeconds.load()}, - logv2::LogSeverity::Warning(), - logv2::LogSeverity::Debug(2)); - } - - synchronized_value<std::unique_ptr<Suppressor>> _supressor{_makeSuppressor()}; -}; - -SeveritySource& getSeveritySource() { - static StaticImmortal<SeveritySource> severitySource{}; - return *severitySource; -} - -} // namespace - -Status onUpdateOfWireOpsWarningPeriod(const int& /*timeout*/) { - // refresh() will fetch the current setting for the suppressor's timeout, which by this time - // will have changed to the new value, so it's OK to ignore the provided new 'timeout' setting - // here (which allows us to localize suppressor creation in 'SeveritySource' class.) - getSeveritySource().refresh(); - return Status::OK(); -} - -void warnUnsupportedOp(Client& client, StringData op) { - std::string clientKey; - BSONObj clientInfo; - if (auto clientMetadata = ClientMetadata::get(&client); clientMetadata) { - auto clientMetadataDoc = clientMetadata->getDocument(); - clientKey = "{}{}{}"_format(clientMetadata->getApplicationName(), - clientMetadataDoc["driver"]["name"].toString(), - clientMetadataDoc["driver"]["version"].toString()); - clientInfo = clientMetadataDoc; - } else { - clientKey = "{}"_format(client.clientAddress()); - clientInfo = BSON("address" << client.clientAddress(/*includePort*/ true)); - } - - LOGV2_DEBUG(5578800, - getSeveritySource().get(clientKey).toInt(), - "Received wire protocol op code or command that is no longer supported. " - "The client driver may require an upgrade. " - "For more details see https://dochub.mongodb.org/core/legacy-opcode-removal", - "op"_attr = op, - "clientInfo"_attr = clientInfo); -} - -void checkAllowedOpQueryCommand(Client& client, StringData cmd) { - static constexpr std::array allowedOpQueryCommands{ - "_isSelf"_sd, - "authenticate"_sd, - "buildinfo"_sd, - "buildInfo"_sd, - "hello"_sd, - "isMaster"_sd, - "ismaster"_sd, - "saslContinue"_sd, - "saslStart"_sd, - }; - - if (std::find(allowedOpQueryCommands.begin(), allowedOpQueryCommands.end(), cmd) == - allowedOpQueryCommands.end()) { - warnUnsupportedOp(client, networkOpToString(dbQuery)); - globalOpCounters.gotQueryDeprecated(); - uasserted( - ErrorCodes::UnsupportedOpQueryCommand, - "Unsupported OP_QUERY command: {}. The client driver may require an upgrade. " - "For more details see https://dochub.mongodb.org/core/legacy-opcode-removal"_format( - cmd)); - } -} - -} // namespace mongo diff --git a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp index 83900625783..2e7766c4767 100644 --- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp @@ -30,7 +30,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/commands.h" -#include "mongo/rpc/warn_unsupported_wire_ops.h" +#include "mongo/rpc/check_allowed_op_query_cmd.h" namespace mongo { namespace { @@ -62,7 +62,6 @@ public: } virtual bool run(OperationContext*, const std::string&, const BSONObj&, BSONObjBuilder&) { - warnUnsupportedOp(cc(), "getLastError"); uasserted(5739001, "getLastError command is not supported"); return false; } diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 58d70ed8dc1..aa794fe35d9 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -67,6 +67,7 @@ #include "mongo/db/views/resolved_view.h" #include "mongo/db/write_concern_options.h" #include "mongo/logv2/log.h" +#include "mongo/rpc/check_allowed_op_query_cmd.h" #include "mongo/rpc/factory.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/rpc/metadata/client_metadata.h" @@ -74,7 +75,6 @@ #include "mongo/rpc/op_msg.h" #include "mongo/rpc/op_msg_rpc_impls.h" #include "mongo/rpc/rewrite_state_change_errors.h" -#include "mongo/rpc/warn_unsupported_wire_ops.h" #include "mongo/s/catalog_cache.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_commands_helpers.h" diff --git a/src/mongo/s/service_entry_point_mongos.cpp b/src/mongo/s/service_entry_point_mongos.cpp index 51ce8aa4d2d..38a3710189b 100644 --- a/src/mongo/s/service_entry_point_mongos.cpp +++ b/src/mongo/s/service_entry_point_mongos.cpp @@ -46,8 +46,8 @@ #include "mongo/db/session_catalog.h" #include "mongo/db/stats/counters.h" #include "mongo/logv2/log.h" +#include "mongo/rpc/check_allowed_op_query_cmd.h" #include "mongo/rpc/message.h" -#include "mongo/rpc/warn_unsupported_wire_ops.h" #include "mongo/s/commands/strategy.h" #include "mongo/s/grid.h" #include "mongo/s/load_balancer_support.h" @@ -138,8 +138,6 @@ Future<DbResponse> HandleRequest::handleRequest() { switch (op) { case dbQuery: if (!nsString.isCommand()) { - globalOpCounters.gotQueryDeprecated(); - warnUnsupportedOp(*(rec->getOpCtx()->getClient()), networkOpToString(dbQuery)); return Future<DbResponse>::makeReady( makeErrorResponseToUnsupportedOpQuery("OP_QUERY is no longer supported")); } @@ -147,28 +145,17 @@ Future<DbResponse> HandleRequest::handleRequest() { case dbMsg: return std::make_unique<CommandOpRunner>(shared_from_this())->run(); case dbGetMore: { - globalOpCounters.gotGetMoreDeprecated(); - warnUnsupportedOp(*(rec->getOpCtx()->getClient()), networkOpToString(dbGetMore)); return Future<DbResponse>::makeReady( makeErrorResponseToUnsupportedOpQuery("OP_GET_MORE is no longer supported")); } case dbKillCursors: - globalOpCounters.gotKillCursorsDeprecated(); - warnUnsupportedOp(*(rec->getOpCtx()->getClient()), networkOpToString(op)); uasserted(5745707, "OP_KILL_CURSORS is no longer supported"); case dbInsert: { - auto opInsert = InsertOp::parseLegacy(rec->getMessage()); - globalOpCounters.gotInsertsDeprecated(opInsert.getDocuments().size()); - warnUnsupportedOp(*(rec->getOpCtx()->getClient()), networkOpToString(op)); uasserted(5745706, "OP_INSERT is no longer supported"); } case dbUpdate: - globalOpCounters.gotUpdateDeprecated(); - warnUnsupportedOp(*(rec->getOpCtx()->getClient()), networkOpToString(op)); uasserted(5745705, "OP_UPDATE is no longer supported"); case dbDelete: - globalOpCounters.gotDeleteDeprecated(); - warnUnsupportedOp(*(rec->getOpCtx()->getClient()), networkOpToString(op)); uasserted(5745704, "OP_DELETE is no longer supported"); default: MONGO_UNREACHABLE; |