summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-09-25 12:35:38 -0400
committerDavid Storch <david.storch@10gen.com>2014-09-25 18:08:57 -0400
commit77b00970997d13d0758c745e5a94fc79982d4401 (patch)
tree2eba1844a398aa2188755553cbfec4f3a1f86d49
parentf12b81dd15143d62768a4082f11ccc26692d6625 (diff)
downloadmongo-77b00970997d13d0758c745e5a94fc79982d4401.tar.gz
SERVER-15233 allow plan cache commands to run on secondaries is slaveOk explicitly set to true
-rw-r--r--jstests/replsets/plan_cache_slaveok.js68
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp4
-rw-r--r--src/mongo/db/commands/plan_cache_commands.h2
-rw-r--r--src/mongo/s/commands/cluster_plan_cache_cmd.cpp8
4 files changed, 80 insertions, 2 deletions
diff --git a/jstests/replsets/plan_cache_slaveok.js b/jstests/replsets/plan_cache_slaveok.js
new file mode 100644
index 00000000000..65d2d36cd18
--- /dev/null
+++ b/jstests/replsets/plan_cache_slaveok.js
@@ -0,0 +1,68 @@
+// Verify that the plan cache commands can be run on secondaries, but only
+// if slave ok is explicitly set.
+
+var name = "plan_cache_slaveok";
+
+function assertPlanCacheCommandsSucceed(db) {
+ // .listQueryShapes()
+ assert.commandWorked(db.runCommand({
+ planCacheListQueryShapes: name
+ }));
+
+ // .getPlansByQuery()
+ assert.commandWorked(db.runCommand({
+ planCacheListPlans: name,
+ query: {a: 1}
+ }));
+
+ // .clear()
+ assert.commandWorked(db.runCommand({
+ planCacheClear: name,
+ query: {a: 1}
+ }));
+}
+
+function assertPlanCacheCommandsFail(db) {
+ // .listQueryShapes()
+ assert.commandFailed(db.runCommand({
+ planCacheListQueryShapes: name
+ }));
+
+ // .getPlansByQuery()
+ assert.commandFailed(db.runCommand({
+ planCacheListPlans: name,
+ query: {a: 1}
+ }));
+
+ // .clear()
+ assert.commandFailed(db.runCommand({
+ planCacheClear: name,
+ query: {a: 1}
+ }));
+}
+
+print("Start replica set with two nodes");
+var replTest = new ReplSetTest({name: name, nodes: 2});
+var nodes = replTest.startSet();
+replTest.initiate();
+var primary = replTest.getMaster();
+
+// Insert a document and let it sync to the secondary.
+print("Initial sync");
+primary.getDB("test")[name].insert({a: 1});
+replTest.awaitReplication();
+
+// Check that the document is present on the primary.
+assert.eq(1, primary.getDB("test")[name].findOne({a: 1})["a"]);
+
+// Make sure the plan cache commands succeed on the primary.
+assertPlanCacheCommandsSucceed(primary.getDB("test"));
+
+// With slave ok false, the commands should fail on the secondary.
+var secondary = replTest.getSecondary();
+secondary.getDB("test").getMongo().setSlaveOk(false);
+assertPlanCacheCommandsFail(secondary.getDB("test"));
+
+// With slave ok true, the commands should succeed on the secondary.
+secondary.getDB("test").getMongo().setSlaveOk(true);
+assertPlanCacheCommandsSucceed(secondary.getDB("test"));
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index 6ca998a1b71..601e9b47318 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -141,6 +141,10 @@ namespace mongo {
return false;
}
+ bool PlanCacheCommand::slaveOverrideOk() const {
+ return true;
+ }
+
void PlanCacheCommand::help(stringstream& ss) const {
ss << helpText;
}
diff --git a/src/mongo/db/commands/plan_cache_commands.h b/src/mongo/db/commands/plan_cache_commands.h
index 1a4a49a3c4f..34660d9a48b 100644
--- a/src/mongo/db/commands/plan_cache_commands.h
+++ b/src/mongo/db/commands/plan_cache_commands.h
@@ -65,6 +65,8 @@ namespace mongo {
virtual bool slaveOk() const;
+ virtual bool slaveOverrideOk() const;
+
virtual void help(std::stringstream& ss) const;
/**
diff --git a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp
index 1aa015a495b..5bd87f4eb8a 100644
--- a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp
+++ b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp
@@ -58,6 +58,10 @@ namespace mongo {
return false;
}
+ bool slaveOverrideOk() const {
+ return true;
+ }
+
virtual bool isWriteCommandForConfigServer() const { return false; }
void help(stringstream& ss) const {
@@ -69,11 +73,11 @@ namespace mongo {
const BSONObj& cmdObj ) {
AuthorizationSession* authzSession = client->getAuthorizationSession();
ResourcePattern pattern = parseResourcePattern(dbname, cmdObj);
-
+
if (authzSession->isAuthorizedForActionsOnResource(pattern, _actionType)) {
return Status::OK();
}
-
+
return Status(ErrorCodes::Unauthorized, "unauthorized");
}