mirror of https://github.com/mongodb/mongo
SERVER-102869: Make $mergeCursors internal (#34111)
GitOrigin-RevId: 8614d4d8831b08ea0f0156fdb6646a21bed348ec
This commit is contained in:
parent
01446737d1
commit
6cf88233f0
|
|
@ -32,7 +32,7 @@ const testInternalClient = (function createInternalClient() {
|
||||||
|
|
||||||
const curDB = testInternalClient.getDB(dbName);
|
const curDB = testInternalClient.getDB(dbName);
|
||||||
|
|
||||||
// Tests that the internal stage '$mergeCursors' does not throw 'ApiStrictError' with an internal
|
// Tests that the internal stage '$mergeCursors' is allowed in requests with an internal
|
||||||
// client and 'apiStrict' set to true.
|
// client and 'apiStrict' set to true.
|
||||||
let result = curDB.runCommand({
|
let result = curDB.runCommand({
|
||||||
aggregate: collName,
|
aggregate: collName,
|
||||||
|
|
@ -52,8 +52,8 @@ let result = curDB.runCommand({
|
||||||
});
|
});
|
||||||
assert.commandWorked(result);
|
assert.commandWorked(result);
|
||||||
|
|
||||||
// Tests that the internal stage '$mergeCursors' throws 'ApiStrictError' with default external
|
// Tests that the internal stage '$mergeCursors' is not allowed in user requests with default
|
||||||
// client when 'apiStrict' is set to true.
|
// external client when 'apiStrict' is set to true.
|
||||||
result = testDB.runCommand({
|
result = testDB.runCommand({
|
||||||
aggregate: collName,
|
aggregate: collName,
|
||||||
pipeline: [{
|
pipeline: [{
|
||||||
|
|
@ -70,9 +70,9 @@ result = testDB.runCommand({
|
||||||
apiVersion: "1",
|
apiVersion: "1",
|
||||||
apiStrict: true
|
apiStrict: true
|
||||||
});
|
});
|
||||||
assert.commandFailedWithCode(result, ErrorCodes.APIStrictError);
|
assert.commandFailedWithCode(result, 5491300);
|
||||||
|
|
||||||
// Tests that the internal stage '$mergeCursors' should not fail with 'ApiStrictError' with default
|
// Tests that the internal stage '$mergeCursors' is not allowed with default
|
||||||
// external client without specifying 'apiStrict' flag.
|
// external client without specifying 'apiStrict' flag.
|
||||||
result = testDB.runCommand({
|
result = testDB.runCommand({
|
||||||
aggregate: collName,
|
aggregate: collName,
|
||||||
|
|
@ -89,7 +89,7 @@ result = testDB.runCommand({
|
||||||
writeConcern: {w: "majority"},
|
writeConcern: {w: "majority"},
|
||||||
apiVersion: "1"
|
apiVersion: "1"
|
||||||
});
|
});
|
||||||
assert.commandWorked(result);
|
assert.commandFailedWithCode(result, 5491300);
|
||||||
|
|
||||||
// Tests that the 'exchange' option cannot be specified by external client with 'apiStrict' set to
|
// Tests that the 'exchange' option cannot be specified by external client with 'apiStrict' set to
|
||||||
// true.
|
// true.
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
/**
|
|
||||||
* SERVER-95350: Fix jstests/aggregation/api_version_stage_allowance_checks.js.
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
load("jstests/libs/collection_drop_recreate.js"); // For assertDropAndRecreateCollection.
|
|
||||||
|
|
||||||
const collName = 'test';
|
|
||||||
assertDropAndRecreateCollection(db, collName);
|
|
||||||
|
|
||||||
let docs = [];
|
|
||||||
for (let i = 0; i < 10; ++i) {
|
|
||||||
docs.push({x: i, y: i, z: i});
|
|
||||||
}
|
|
||||||
db[collName].insertMany(docs);
|
|
||||||
|
|
||||||
assert.commandWorked(db.runCommand({
|
|
||||||
explain: {
|
|
||||||
aggregate: collName,
|
|
||||||
pipeline: [{
|
|
||||||
$mergeCursors: {
|
|
||||||
sort: {y: 1, z: 1},
|
|
||||||
compareWholeSortKey: false,
|
|
||||||
remotes: [],
|
|
||||||
nss: "test.mergeCursors",
|
|
||||||
allowPartialResults: false,
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
cursor: {},
|
|
||||||
readConcern: {},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}());
|
|
||||||
|
|
@ -7053,6 +7053,42 @@ export const authCommandsLib = {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testname: "aggregate_$mergeCursors",
|
||||||
|
command: {
|
||||||
|
aggregate: "foo",
|
||||||
|
pipeline: [{
|
||||||
|
$mergeCursors: {
|
||||||
|
sort: {y: 1, z: 1},
|
||||||
|
compareWholeSortKey: false,
|
||||||
|
remotes: [],
|
||||||
|
nss: "test.mergeCursors",
|
||||||
|
allowPartialResults: false,
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
cursor: {},
|
||||||
|
},
|
||||||
|
testcases: [
|
||||||
|
{
|
||||||
|
runOnDb: firstDbName,
|
||||||
|
roles: {__system: 1},
|
||||||
|
// $mergeCursors requires __system role OR a user with internal and find action types as privileges.
|
||||||
|
expectFail: true,
|
||||||
|
privileges: [
|
||||||
|
{resource: {cluster: true}, actions: ["internal"]},
|
||||||
|
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
runOnDb: firstDbName,
|
||||||
|
// Find action type as a privilege alone is not sufficient for $mergeCursors.
|
||||||
|
expectAuthzFailure: true,
|
||||||
|
privileges: [
|
||||||
|
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
testname: "validate_db_metadata_command_specific_db",
|
testname: "validate_db_metadata_command_specific_db",
|
||||||
command: {
|
command: {
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,32 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LiteParsedDocumentSourceInternal final : public LiteParsedDocumentSource {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates the default LiteParsedDocumentSource for internal document sources. This requires
|
||||||
|
* the privilege on 'internal' action. This should still be used with caution. Make sure your
|
||||||
|
* stage doesn't need to communicate any special behavior before registering a DocumentSource
|
||||||
|
* using this parser.
|
||||||
|
*/
|
||||||
|
static std::unique_ptr<LiteParsedDocumentSourceInternal> parse(const NamespaceString& nss,
|
||||||
|
const BSONElement& spec) {
|
||||||
|
return std::make_unique<LiteParsedDocumentSourceInternal>(spec.fieldName());
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteParsedDocumentSourceInternal(std::string parseTimeName)
|
||||||
|
: LiteParsedDocumentSource(std::move(parseTimeName)) {}
|
||||||
|
|
||||||
|
stdx::unordered_set<NamespaceString> getInvolvedNamespaces() const final {
|
||||||
|
return stdx::unordered_set<NamespaceString>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivilegeVector requiredPrivileges(bool isMongos, bool bypassDocumentValidation) const final {
|
||||||
|
return {Privilege(ResourcePattern::forClusterResource(), ActionSet{ActionType::internal})};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for DocumentSources which reference a foreign collection.
|
* Helper class for DocumentSources which reference a foreign collection.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@
|
||||||
|
|
||||||
namespace mongo {
|
namespace mongo {
|
||||||
|
|
||||||
REGISTER_DOCUMENT_SOURCE(mergeCursors,
|
REGISTER_INTERNAL_DOCUMENT_SOURCE(mergeCursors,
|
||||||
LiteParsedDocumentSourceDefault::parse,
|
LiteParsedDocumentSourceInternal::parse,
|
||||||
DocumentSourceMergeCursors::createFromBson,
|
DocumentSourceMergeCursors::createFromBson,
|
||||||
AllowedWithApiStrict::kInternal);
|
true);
|
||||||
|
|
||||||
constexpr StringData DocumentSourceMergeCursors::kStageName;
|
constexpr StringData DocumentSourceMergeCursors::kStageName;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue