summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/client/SConscript1
-rw-r--r--src/mongo/client/async_client.cpp3
-rw-r--r--src/mongo/client/authenticate.cpp17
-rw-r--r--src/mongo/client/authenticate.h4
-rw-r--r--src/mongo/client/dbclient_base.cpp11
-rw-r--r--src/mongo/client/native_sasl_client_session.cpp33
-rw-r--r--src/mongo/client/sasl_client_authenticate_impl.cpp4
-rw-r--r--src/mongo/client/scram_client_cache.h23
-rw-r--r--src/mongo/db/commands/SConscript3
-rw-r--r--src/mongo/db/commands/server_status.cpp268
-rw-r--r--src/mongo/db/commands/server_status.h24
-rw-r--r--src/mongo/db/commands/server_status_command.cpp270
-rw-r--r--src/mongo/db/repl/SConscript2
-rw-r--r--src/mongo/executor/connection_pool_tl.cpp4
-rw-r--r--src/mongo/executor/network_connection_hook.h2
15 files changed, 402 insertions, 267 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index 27d48509935..0f8a4903bfa 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -128,6 +128,7 @@ saslClientEnv.Library(
"sasl_aws_client" if get_option('ssl') == 'on' else '',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/commands/server_status_core',
'$BUILD_DIR/mongo/util/net/http_client',
],
SYSLIBDEPS=saslLibs,
diff --git a/src/mongo/client/async_client.cpp b/src/mongo/client/async_client.cpp
index 6b3085efd4d..3fcd468d8d5 100644
--- a/src/mongo/client/async_client.cpp
+++ b/src/mongo/client/async_client.cpp
@@ -98,7 +98,7 @@ BSONObj AsyncDBClient::_buildIsMasterRequest(const std::string& appName,
}
if (hook) {
- return hook->augmentIsMasterRequest(bob.obj());
+ return hook->augmentIsMasterRequest(remote(), bob.obj());
} else {
return bob.obj();
}
@@ -192,6 +192,7 @@ Future<void> AsyncDBClient::authenticateInternal(
#endif
return auth::authenticateInternalClient(clientName,
+ remote(),
mechanismHint,
auth::StepDownBehavior::kKillConnection,
_makeAuthRunCommandHook(),
diff --git a/src/mongo/client/authenticate.cpp b/src/mongo/client/authenticate.cpp
index af3b48f73b1..7180b707f10 100644
--- a/src/mongo/client/authenticate.cpp
+++ b/src/mongo/client/authenticate.cpp
@@ -248,27 +248,28 @@ Future<std::string> negotiateSaslMechanism(RunCommandHook runCommand,
Future<void> authenticateInternalClient(
const std::string& clientSubjectName,
+ const HostAndPort& remote,
boost::optional<std::string> mechanismHint,
StepDownBehavior stepDownBehavior,
RunCommandHook runCommand,
std::shared_ptr<InternalAuthParametersProvider> internalParamsProvider) {
return negotiateSaslMechanism(
runCommand, internalSecurity.user->getName(), mechanismHint, stepDownBehavior)
- .then([runCommand, clientSubjectName, internalParamsProvider](
+ .then([runCommand, clientSubjectName, remote, internalParamsProvider](
std::string mechanism) -> Future<void> {
auto params = internalParamsProvider->get(0, mechanism);
if (params.isEmpty()) {
return Status(ErrorCodes::BadValue,
"Missing authentication parameters for internal user auth");
}
- return authenticateClient(params, HostAndPort(), clientSubjectName, runCommand)
+ return authenticateClient(params, remote, clientSubjectName, runCommand)
.onError<ErrorCodes::AuthenticationFailed>(
- [runCommand, clientSubjectName, mechanism, internalParamsProvider](
+ [runCommand, clientSubjectName, remote, mechanism, internalParamsProvider](
Status status) -> Future<void> {
auto altCreds = internalParamsProvider->get(1, mechanism);
if (!altCreds.isEmpty()) {
return authenticateClient(
- altCreds, HostAndPort(), clientSubjectName, runCommand);
+ altCreds, remote, clientSubjectName, runCommand);
}
return status;
});
@@ -391,7 +392,9 @@ SpeculativeAuthType speculateAuth(BSONObjBuilder* isMasterRequest,
}
SpeculativeAuthType speculateInternalAuth(
- BSONObjBuilder* isMasterRequest, std::shared_ptr<SaslClientSession>* saslClientSession) try {
+ const HostAndPort& remoteHost,
+ BSONObjBuilder* isMasterRequest,
+ std::shared_ptr<SaslClientSession>* saslClientSession) try {
auto params = getInternalAuthParams(0, kMechanismScramSha256.toString());
if (params.isEmpty()) {
return SpeculativeAuthType::kNone;
@@ -400,8 +403,8 @@ SpeculativeAuthType speculateInternalAuth(
auto mechanism = getBSONString(params, saslCommandMechanismFieldName);
auto authDB = getBSONString(params, saslCommandUserDBFieldName);
- auto ret = _speculateAuth(
- isMasterRequest, mechanism, HostAndPort(), authDB, params, saslClientSession);
+ auto ret =
+ _speculateAuth(isMasterRequest, mechanism, remoteHost, authDB, params, saslClientSession);
if (!ret.isOK()) {
return SpeculativeAuthType::kNone;
}
diff --git a/src/mongo/client/authenticate.h b/src/mongo/client/authenticate.h
index 1a5fe609665..b5b4876c573 100644
--- a/src/mongo/client/authenticate.h
+++ b/src/mongo/client/authenticate.h
@@ -147,6 +147,7 @@ Future<void> authenticateClient(const BSONObj& params,
*/
Future<void> authenticateInternalClient(
const std::string& clientSubjectName,
+ const HostAndPort& remote,
boost::optional<std::string> mechanismHint,
StepDownBehavior stepDownBehavior,
RunCommandHook runCommand,
@@ -205,7 +206,8 @@ SpeculativeAuthType speculateAuth(BSONObjBuilder* isMasterRequest,
* Constructs a "speculativeAuthenticate" or "speculativeSaslStart"
* payload for an isMaster request using internal (intracluster) authentication.
*/
-SpeculativeAuthType speculateInternalAuth(BSONObjBuilder* isMasterRequest,
+SpeculativeAuthType speculateInternalAuth(const HostAndPort& remoteHost,
+ BSONObjBuilder* isMasterRequest,
std::shared_ptr<SaslClientSession>* saslClientSession);
} // namespace auth
diff --git a/src/mongo/client/dbclient_base.cpp b/src/mongo/client/dbclient_base.cpp
index dce2f0a5b2a..2eecc7ae6ec 100644
--- a/src/mongo/client/dbclient_base.cpp
+++ b/src/mongo/client/dbclient_base.cpp
@@ -428,10 +428,13 @@ Status DBClientBase::authenticateInternalUser(auth::StepDownBehavior stepDownBeh
#endif
auto authProvider = auth::createDefaultInternalAuthProvider();
- auto status =
- auth::authenticateInternalClient(
- clientName, boost::none, stepDownBehavior, _makeAuthRunCommandHook(), authProvider)
- .getNoThrow();
+ auto status = auth::authenticateInternalClient(clientName,
+ HostAndPort(getServerAddress()),
+ boost::none,
+ stepDownBehavior,
+ _makeAuthRunCommandHook(),
+ authProvider)
+ .getNoThrow();
if (status.isOK()) {
return status;
}
diff --git a/src/mongo/client/native_sasl_client_session.cpp b/src/mongo/client/native_sasl_client_session.cpp
index 3d37f9db9cc..146c344e42e 100644
--- a/src/mongo/client/native_sasl_client_session.cpp
+++ b/src/mongo/client/native_sasl_client_session.cpp
@@ -32,6 +32,7 @@
#include "mongo/client/native_sasl_client_session.h"
#include "mongo/base/init.h"
+#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/client/sasl_client_conversation.h"
#include "mongo/client/sasl_plain_client_conversation.h"
#include "mongo/client/sasl_scram_client_conversation.h"
@@ -39,6 +40,7 @@
#include "mongo/config.h"
#include "mongo/crypto/sha1_block.h"
#include "mongo/crypto/sha256_block.h"
+#include "mongo/db/commands/server_status.h"
#include "mongo/util/str.h"
#ifdef MONGO_CONFIG_SSL
@@ -60,6 +62,37 @@ MONGO_INITIALIZER(NativeSaslClientContext)(InitializerContext* context) {
auto* scramsha1ClientCache = new SCRAMClientCache<SHA1Block>;
auto* scramsha256ClientCache = new SCRAMClientCache<SHA256Block>;
+template <typename HashBlock>
+void cacheToBSON(SCRAMClientCache<HashBlock>* cache, StringData name, BSONObjBuilder* builder) {
+ auto stats = cache->getStats();
+
+ BSONObjBuilder sub(builder->subobjStart(name));
+ sub.append("count", stats.count);
+ sub.append("hits", stats.hits);
+ sub.append("misses", stats.misses);
+}
+
+/**
+ * Output stats about the SCRAM client cache to server status.
+ */
+class ScramCacheStatsStatusSection : ServerStatusSection {
+public:
+ ScramCacheStatsStatusSection() : ServerStatusSection("scramCache") {}
+
+ bool includeByDefault() const override {
+ return true;
+ }
+
+ BSONObj generateSection(OperationContext* opCtx,
+ const BSONElement& configElement) const override {
+ BSONObjBuilder builder;
+ cacheToBSON(scramsha1ClientCache, "SCRAM-SHA-1", &builder);
+ cacheToBSON(scramsha256ClientCache, "SCRAM-SHA-256", &builder);
+ return builder.obj();
+ };
+
+} scramCacheStatusSection;
+
} // namespace
NativeSaslClientSession::NativeSaslClientSession()
diff --git a/src/mongo/client/sasl_client_authenticate_impl.cpp b/src/mongo/client/sasl_client_authenticate_impl.cpp
index 323f7a6b321..3c9bd422270 100644
--- a/src/mongo/client/sasl_client_authenticate_impl.cpp
+++ b/src/mongo/client/sasl_client_authenticate_impl.cpp
@@ -117,6 +117,10 @@ Status saslConfigureSession(SaslClientSession* session,
const HostAndPort& hostname,
StringData targetDatabase,
const BSONObj& saslParameters) {
+ // SERVER-59876 Ensure hostname is never empty. If it is empty, the client-side SCRAM cache will
+ // not be used which creates performance problems.
+ dassert(!hostname.empty());
+
std::string mechanism;
Status status =
bsonExtractStringField(saslParameters, saslCommandMechanismFieldName, &mechanism);
diff --git a/src/mongo/client/scram_client_cache.h b/src/mongo/client/scram_client_cache.h
index fb43d76b622..d8cc4493cb8 100644
--- a/src/mongo/client/scram_client_cache.h
+++ b/src/mongo/client/scram_client_cache.h
@@ -68,6 +68,15 @@ private:
using HostToSecretsMap = stdx::unordered_map<HostAndPort, HostToSecretsPair>;
public:
+ struct Stats {
+ // Count of cache entries
+ int64_t count{0};
+ // Number of cache hits
+ int64_t hits{0};
+ // Number of cache misses
+ int64_t misses{0};
+ };
+
/**
* Returns precomputed SCRAMSecrets, if one has already been
* stored for the specified hostname and the provided presecrets
@@ -81,6 +90,7 @@ public:
// Search the cache for a record associated with the host we're trying to connect to.
auto foundSecret = _hostToSecrets.find(target);
if (foundSecret == _hostToSecrets.end()) {
+ ++_stats.misses;
return {};
}
@@ -89,8 +99,10 @@ public:
// stale cached secrets. We'll need to rerun the SCRAM computation.
const auto& foundPresecrets = foundSecret->second.first;
if (foundPresecrets == presecrets) {
+ ++_stats.hits;
return foundSecret->second.second;
} else {
+ ++_stats.misses;
return {};
}
}
@@ -116,9 +128,20 @@ public:
}
}
+ /**
+ * Return metrics about the cache
+ */
+ Stats getStats() const {
+ const stdx::lock_guard<Latch> lock(_hostToSecretsMutex);
+ Stats stats = _stats;
+ stats.count = _hostToSecrets.size();
+ return stats;
+ }
+
private:
mutable Mutex _hostToSecretsMutex = MONGO_MAKE_LATCH("SCRAMClientCache::_hostToSecretsMutex");
HostToSecretsMap _hostToSecrets;
+ mutable Stats _stats;
};
} // namespace mongo
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index 3d72dd2dbd7..cc726b7385f 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -21,6 +21,7 @@ env.Library(
env.Library(
target='server_status_core',
source=[
+ 'server_status.cpp',
'server_status_internal.cpp',
'server_status_metric.cpp',
],
@@ -32,7 +33,7 @@ env.Library(
env.Library(
target='server_status',
source=[
- 'server_status.cpp',
+ 'server_status_command.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/commands',
diff --git a/src/mongo/db/commands/server_status.cpp b/src/mongo/db/commands/server_status.cpp
index a41f0545ac3..b7e6c5d3a24 100644
--- a/src/mongo/db/commands/server_status.cpp
+++ b/src/mongo/db/commands/server_status.cpp
@@ -27,274 +27,44 @@
* it in the license file.
*/
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand
-
#include "mongo/platform/basic.h"
-#include "mongo/db/auth/authorization_session.h"
-#include "mongo/db/commands.h"
#include "mongo/db/commands/server_status.h"
+
#include "mongo/db/commands/server_status_internal.h"
#include "mongo/db/service_context.h"
-#include "mongo/db/stats/counters.h"
-#include "mongo/logv2/log.h"
-#include "mongo/util/net/http_client.h"
-#include "mongo/util/net/socket_utils.h"
#include "mongo/util/version.h"
namespace mongo {
-using std::endl;
-using std::map;
-using std::string;
-using std::stringstream;
-
namespace {
constexpr auto kTimingSection = "timing"_sd;
} // namespace
-class CmdServerStatus : public BasicCommand {
-public:
- CmdServerStatus() : BasicCommand("serverStatus"), _started(Date_t::now()), _runCalled(false) {}
-
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
- return false;
- }
- AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
- return AllowedOnSecondary::kAlways;
- }
- virtual bool allowsAfterClusterTime(const BSONObj& cmdObj) const override {
- return false;
- }
- std::string help() const override {
- return "returns lots of administrative server statistics";
- }
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) const {
- ActionSet actions;
- actions.addAction(ActionType::serverStatus);
- out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
- }
- bool run(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- _runCalled.store(true);
-
- const auto service = opCtx->getServiceContext();
- const auto clock = service->getFastClockSource();
- const auto runStart = clock->now();
- BSONObjBuilder timeBuilder(256);
-
- const auto authSession = AuthorizationSession::get(Client::getCurrent());
-
- // --- basic fields that are global
-
- result.append("host", prettyHostName());
- result.append("version", VersionInfoInterface::instance().version());
- result.append("process", serverGlobalParams.binaryName);
- result.append("pid", ProcessId::getCurrent().asLongLong());
- result.append("uptime", (double)(time(nullptr) - serverGlobalParams.started));
- auto uptime = clock->now() - _started;
- result.append("uptimeMillis", durationCount<Milliseconds>(uptime));
- result.append("uptimeEstimate", durationCount<Seconds>(uptime));
- result.appendDate("localTime", jsTime());
-
- timeBuilder.appendNumber("after basic",
- durationCount<Milliseconds>(clock->now() - runStart));
-
- // --- all sections
-
- for (SectionMap::const_iterator i = _sections.begin(); i != _sections.end(); ++i) {
- ServerStatusSection* section = i->second;
-
- std::vector<Privilege> requiredPrivileges;
- section->addRequiredPrivileges(&requiredPrivileges);
- if (!authSession->isAuthorizedForPrivileges(requiredPrivileges))
- continue;
-
- bool include = section->includeByDefault();
- const auto& elem = cmdObj[section->getSectionName()];
- if (elem.type()) {
- include = elem.trueValue();
- }
-
- if (!include) {
- continue;
- }
-
- section->appendSection(opCtx, elem, &result);
- timeBuilder.appendNumber(
- static_cast<string>(str::stream() << "after " << section->getSectionName()),
- durationCount<Milliseconds>(clock->now() - runStart));
- }
-
- // --- counters
- bool includeMetricTree = MetricTree::theMetricTree != nullptr;
- if (cmdObj["metrics"].type() && !cmdObj["metrics"].trueValue())
- includeMetricTree = false;
-
- if (includeMetricTree) {
- MetricTree::theMetricTree->appendTo(result);
- }
-
- // --- some hard coded global things hard to pull out
-
- auto runElapsed = clock->now() - runStart;
- timeBuilder.appendNumber("at end", durationCount<Milliseconds>(runElapsed));
- if (runElapsed > Milliseconds(1000)) {
- BSONObj t = timeBuilder.obj();
- LOGV2(20499,
- "serverStatus was very slow: {timeStats}",
- "serverStatus was very slow",
- "timeStats"_attr = t);
-
- bool include_timing = true;
- const auto& elem = cmdObj[kTimingSection];
- if (!elem.eoo()) {
- include_timing = elem.trueValue();
- }
-
- if (include_timing) {
- result.append(kTimingSection, t);
- }
- }
-
- return true;
- }
-
- void addSection(ServerStatusSection* section) {
- // Disallow adding a section named "timing" as it is reserved for the server status command.
- dassert(section->getSectionName() != kTimingSection);
- verify(!_runCalled.load());
- _sections[section->getSectionName()] = section;
- }
+ServerStatusSectionRegistry* ServerStatusSectionRegistry::get() {
+ static ServerStatusSectionRegistry instance;
+ return &instance;
+}
-private:
- const Date_t _started;
- AtomicWord<bool> _runCalled;
+void ServerStatusSectionRegistry::addSection(ServerStatusSection* section) {
+ // Disallow adding a section named "timing" as it is reserved for the server status command.
+ dassert(section->getSectionName() != kTimingSection);
+ verify(!_runCalled.load());
+ _sections[section->getSectionName()] = section;
+}
- typedef map<string, ServerStatusSection*> SectionMap;
- SectionMap _sections;
+ServerStatusSectionRegistry::SectionMap::const_iterator ServerStatusSectionRegistry::begin() {
+ _runCalled.store(true);
+ return _sections.begin();
};
-namespace {
-
-// This widget ensures that the serverStatus command is registered even if no
-// server status sections are registered.
-
-const struct CmdServerStatusInstantiator {
- explicit CmdServerStatusInstantiator() {
- getInstance();
- }
-
- static CmdServerStatus& getInstance() {
- static CmdServerStatus instance;
- return instance;
- }
-} kDoNotMentionThisVariable;
-
-} // namespace
-
-ServerStatusSection::ServerStatusSection(const string& sectionName) : _sectionName(sectionName) {
- CmdServerStatusInstantiator::getInstance().addSection(this);
+ServerStatusSectionRegistry::SectionMap::const_iterator ServerStatusSectionRegistry::end() {
+ return _sections.end();
}
-OpCounterServerStatusSection::OpCounterServerStatusSection(const string& sectionName,
- OpCounters* counters)
- : ServerStatusSection(sectionName), _counters(counters) {}
-
-BSONObj OpCounterServerStatusSection::generateSection(OperationContext* opCtx,
- const BSONElement& configElement) const {
- return _counters->getObj();
+ServerStatusSection::ServerStatusSection(const std::string& sectionName)
+ : _sectionName(sectionName) {
+ ServerStatusSectionRegistry::get()->addSection(this);
}
-OpCounterServerStatusSection globalOpCounterServerStatusSection("opcounters", &globalOpCounters);
-
-
-namespace {
-
-// some universal sections
-
-class ExtraInfo : public ServerStatusSection {
-public:
- ExtraInfo() : ServerStatusSection("extra_info") {}
-
- bool includeByDefault() const override {
- return true;
- }
-
- BSONObj generateSection(OperationContext* opCtx,
- const BSONElement& configElement) const override {
- BSONObjBuilder bb;
-
- bb.append("note", "fields vary by platform");
- ProcessInfo p;
- p.getExtraInfo(bb);
-
- return bb.obj();
- }
-
-} extraInfo;
-
-class Asserts : public ServerStatusSection {
-public:
- Asserts() : ServerStatusSection("asserts") {}
-
- bool includeByDefault() const override {
- return true;
- }
-
- BSONObj generateSection(OperationContext* opCtx,
- const BSONElement& configElement) const override {
- BSONObjBuilder asserts;
- asserts.append("regular", assertionCount.regular.loadRelaxed());
- asserts.append("warning", assertionCount.warning.loadRelaxed());
- asserts.append("msg", assertionCount.msg.loadRelaxed());
- asserts.append("user", assertionCount.user.loadRelaxed());
- asserts.append("tripwire", assertionCount.tripwire.loadRelaxed());
- asserts.append("rollovers", assertionCount.rollovers.loadRelaxed());
- return asserts.obj();
- }
-
-} asserts;
-
-class MemBase : public ServerStatusMetric {
-public:
- MemBase() : ServerStatusMetric(".mem.bits") {}
- virtual void appendAtLeaf(BSONObjBuilder& b) const {
- b.append("bits", sizeof(int*) == 4 ? 32 : 64);
-
- ProcessInfo p;
- int v = 0;
- if (p.supported()) {
- b.appendNumber("resident", p.getResidentSize());
- v = p.getVirtualMemorySize();
- b.appendNumber("virtual", v);
- b.appendBool("supported", true);
- } else {
- b.append("note", "not all mem info support on this platform");
- b.appendBool("supported", false);
- }
- }
-} memBase;
-
-class HttpClientServerStatus : public ServerStatusSection {
-public:
- HttpClientServerStatus() : ServerStatusSection("http_client") {}
-
- bool includeByDefault() const final {
- return false;
- }
-
- void addRequiredPrivileges(std::vector<Privilege>* out) final {}
-
- BSONObj generateSection(OperationContext*, const BSONElement& configElement) const final {
- return HttpClient::getServerStatus();
- }
-} httpClientServerStatus;
-
-} // namespace
-
} // namespace mongo
diff --git a/src/mongo/db/commands/server_status.h b/src/mongo/db/commands/server_status.h
index c803710bff6..d4b8b59e025 100644
--- a/src/mongo/db/commands/server_status.h
+++ b/src/mongo/db/commands/server_status.h
@@ -107,6 +107,30 @@ private:
const std::string _sectionName;
};
+/**
+ * Class the keeps a map of all registered status sections
+ */
+class ServerStatusSectionRegistry {
+public:
+ using SectionMap = std::map<std::string, ServerStatusSection*>;
+
+ static ServerStatusSectionRegistry* get();
+
+ /**
+ * Add a status section to the map. Called by ServerStatusSection constructor
+ */
+ void addSection(ServerStatusSection* section);
+
+ SectionMap::const_iterator begin();
+
+ SectionMap::const_iterator end();
+
+private:
+ AtomicWord<bool> _runCalled{false};
+
+ SectionMap _sections;
+};
+
class OpCounterServerStatusSection : public ServerStatusSection {
public:
OpCounterServerStatusSection(const std::string& sectionName, OpCounters* counters);
diff --git a/src/mongo/db/commands/server_status_command.cpp b/src/mongo/db/commands/server_status_command.cpp
new file mode 100644
index 00000000000..f099766e564
--- /dev/null
+++ b/src/mongo/db/commands/server_status_command.cpp
@@ -0,0 +1,270 @@
+/**
+ * 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.
+ */
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/server_status.h"
+#include "mongo/db/commands/server_status_internal.h"
+#include "mongo/db/service_context.h"
+#include "mongo/db/stats/counters.h"
+#include "mongo/logv2/log.h"
+#include "mongo/util/net/http_client.h"
+#include "mongo/util/net/socket_utils.h"
+#include "mongo/util/version.h"
+
+namespace mongo {
+namespace {
+constexpr auto kTimingSection = "timing"_sd;
+
+class CmdServerStatus : public BasicCommand {
+public:
+ CmdServerStatus() : BasicCommand("serverStatus"), _started(Date_t::now()) {}
+
+ bool supportsWriteConcern(const BSONObj& cmd) const final {
+ return false;
+ }
+
+ AllowedOnSecondary secondaryAllowed(ServiceContext*) const final {
+ return AllowedOnSecondary::kAlways;
+ }
+
+ bool allowsAfterClusterTime(const BSONObj& cmdObj) const final {
+ return false;
+ }
+
+ std::string help() const final {
+ return "returns lots of administrative server statistics";
+ }
+
+ void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out) const final {
+ ActionSet actions;
+ actions.addAction(ActionType::serverStatus);
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
+ }
+
+ bool run(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder& result) final {
+ const auto service = opCtx->getServiceContext();
+ const auto clock = service->getFastClockSource();
+ const auto runStart = clock->now();
+ BSONObjBuilder timeBuilder(256);
+
+ const auto authSession = AuthorizationSession::get(Client::getCurrent());
+
+ // --- basic fields that are global
+
+ result.append("host", prettyHostName());
+ result.append("version", VersionInfoInterface::instance().version());
+ result.append("process", serverGlobalParams.binaryName);
+ result.append("pid", ProcessId::getCurrent().asLongLong());
+ result.append("uptime", (double)(time(nullptr) - serverGlobalParams.started));
+ auto uptime = clock->now() - _started;
+ result.append("uptimeMillis", durationCount<Milliseconds>(uptime));
+ result.append("uptimeEstimate", durationCount<Seconds>(uptime));
+ result.appendDate("localTime", jsTime());
+
+ timeBuilder.appendNumber("after basic",
+ durationCount<Milliseconds>(clock->now() - runStart));
+
+ // --- all sections
+ auto registry = ServerStatusSectionRegistry::get();
+ for (auto i = registry->begin(); i != registry->end(); ++i) {
+ ServerStatusSection* section = i->second;
+
+ std::vector<Privilege> requiredPrivileges;
+ section->addRequiredPrivileges(&requiredPrivileges);
+ if (!authSession->isAuthorizedForPrivileges(requiredPrivileges))
+ continue;
+
+ bool include = section->includeByDefault();
+ const auto& elem = cmdObj[section->getSectionName()];
+ if (elem.type()) {
+ include = elem.trueValue();
+ }
+
+ if (!include) {
+ continue;
+ }
+
+ section->appendSection(opCtx, elem, &result);
+ timeBuilder.appendNumber(
+ static_cast<std::string>(str::stream() << "after " << section->getSectionName()),
+ durationCount<Milliseconds>(clock->now() - runStart));
+ }
+
+ // --- counters
+ bool includeMetricTree = MetricTree::theMetricTree != nullptr;
+ if (cmdObj["metrics"].type() && !cmdObj["metrics"].trueValue())
+ includeMetricTree = false;
+
+ if (includeMetricTree) {
+ MetricTree::theMetricTree->appendTo(result);
+ }
+
+ // --- some hard coded global things hard to pull out
+
+ auto runElapsed = clock->now() - runStart;
+ timeBuilder.appendNumber("at end", durationCount<Milliseconds>(runElapsed));
+ if (runElapsed > Milliseconds(1000)) {
+ BSONObj t = timeBuilder.obj();
+ LOGV2(20499,
+ "serverStatus was very slow: {timeStats}",
+ "serverStatus was very slow",
+ "timeStats"_attr = t);
+
+ bool include_timing = true;
+ const auto& elem = cmdObj[kTimingSection];
+ if (!elem.eoo()) {
+ include_timing = elem.trueValue();
+ }
+
+ if (include_timing) {
+ result.append(kTimingSection, t);
+ }
+ }
+
+ return true;
+ }
+
+private:
+ const Date_t _started;
+};
+
+Command* serverStatusCommand;
+
+MONGO_INITIALIZER(CreateCmdServerStatus)(InitializerContext* context) {
+ serverStatusCommand = new CmdServerStatus();
+}
+
+} // namespace
+
+OpCounterServerStatusSection::OpCounterServerStatusSection(const std::string& sectionName,
+ OpCounters* counters)
+ : ServerStatusSection(sectionName), _counters(counters) {}
+
+BSONObj OpCounterServerStatusSection::generateSection(OperationContext* opCtx,
+ const BSONElement& configElement) const {
+ return _counters->getObj();
+}
+
+OpCounterServerStatusSection globalOpCounterServerStatusSection("opcounters", &globalOpCounters);
+
+namespace {
+
+// some universal sections
+
+class ExtraInfo : public ServerStatusSection {
+public:
+ ExtraInfo() : ServerStatusSection("extra_info") {}
+
+ bool includeByDefault() const override {
+ return true;
+ }
+
+ BSONObj generateSection(OperationContext* opCtx,
+ const BSONElement& configElement) const override {
+ BSONObjBuilder bb;
+
+ bb.append("note", "fields vary by platform");
+ ProcessInfo p;
+ p.getExtraInfo(bb);
+
+ return bb.obj();
+ }
+
+} extraInfo;
+
+class Asserts : public ServerStatusSection {
+public:
+ Asserts() : ServerStatusSection("asserts") {}
+
+ bool includeByDefault() const override {
+ return true;
+ }
+
+ BSONObj generateSection(OperationContext* opCtx,
+ const BSONElement& configElement) const override {
+ BSONObjBuilder asserts;
+ asserts.append("regular", assertionCount.regular.loadRelaxed());
+ asserts.append("warning", assertionCount.warning.loadRelaxed());
+ asserts.append("msg", assertionCount.msg.loadRelaxed());
+ asserts.append("user", assertionCount.user.loadRelaxed());
+ asserts.append("tripwire", assertionCount.tripwire.loadRelaxed());
+ asserts.append("rollovers", assertionCount.rollovers.loadRelaxed());
+ return asserts.obj();
+ }
+
+} asserts;
+
+class MemBase : public ServerStatusMetric {
+public:
+ MemBase() : ServerStatusMetric(".mem.bits") {}
+ virtual void appendAtLeaf(BSONObjBuilder& b) const {
+ b.append("bits", sizeof(int*) == 4 ? 32 : 64);
+
+ ProcessInfo p;
+ int v = 0;
+ if (p.supported()) {
+ b.appendNumber("resident", p.getResidentSize());
+ v = p.getVirtualMemorySize();
+ b.appendNumber("virtual", v);
+ b.appendBool("supported", true);
+ } else {
+ b.append("note", "not all mem info support on this platform");
+ b.appendBool("supported", false);
+ }
+ }
+} memBase;
+
+class HttpClientServerStatus : public ServerStatusSection {
+public:
+ HttpClientServerStatus() : ServerStatusSection("http_client") {}
+
+ bool includeByDefault() const final {
+ return false;
+ }
+
+ void addRequiredPrivileges(std::vector<Privilege>* out) final {}
+
+ BSONObj generateSection(OperationContext*, const BSONElement& configElement) const final {
+ return HttpClient::getServerStatus();
+ }
+} httpClientServerStatus;
+
+} // namespace
+
+} // namespace mongo
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript
index 84741093996..1cb28229770 100644
--- a/src/mongo/db/repl/SConscript
+++ b/src/mongo/db/repl/SConscript
@@ -1289,11 +1289,11 @@ env.Library(
"tenant_migration_server_status_section.cpp",
],
LIBDEPS=[
- '$BUILD_DIR/mongo/db/commands/server_status',
"repl_server_parameters",
],
LIBDEPS_PRIVATE=[
"$BUILD_DIR/mongo/base",
+ '$BUILD_DIR/mongo/db/commands/server_status_core',
],
)
diff --git a/src/mongo/executor/connection_pool_tl.cpp b/src/mongo/executor/connection_pool_tl.cpp
index 30383538b1a..547a968ed38 100644
--- a/src/mongo/executor/connection_pool_tl.cpp
+++ b/src/mongo/executor/connection_pool_tl.cpp
@@ -171,7 +171,7 @@ public:
explicit TLConnectionSetupHook(executor::NetworkConnectionHook* hookToWrap, bool x509AuthOnly)
: _wrappedHook(hookToWrap), _x509AuthOnly(x509AuthOnly) {}
- BSONObj augmentIsMasterRequest(BSONObj cmdObj) override {
+ BSONObj augmentIsMasterRequest(const HostAndPort& remoteHost, BSONObj cmdObj) override {
BSONObjBuilder bob(std::move(cmdObj));
bob.append("hangUpOnStepDown", false);
if (internalSecurity.user) {
@@ -181,7 +181,7 @@ public:
if (_x509AuthOnly) {
_speculativeAuthType = auth::SpeculativeAuthType::kAuthenticate;
} else {
- _speculativeAuthType = auth::speculateInternalAuth(&bob, &_session);
+ _speculativeAuthType = auth::speculateInternalAuth(remoteHost, &bob, &_session);
}
return bob.obj();
diff --git a/src/mongo/executor/network_connection_hook.h b/src/mongo/executor/network_connection_hook.h
index 32186b985e6..04de5571cb6 100644
--- a/src/mongo/executor/network_connection_hook.h
+++ b/src/mongo/executor/network_connection_hook.h
@@ -58,7 +58,7 @@ public:
*
* By default this will just return the cmdObj passed in unaltered.
*/
- virtual BSONObj augmentIsMasterRequest(BSONObj cmdObj) {
+ virtual BSONObj augmentIsMasterRequest(const HostAndPort& remoteHost, BSONObj cmdObj) {
return cmdObj;
}