diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-08-29 18:50:25 -0400 |
---|---|---|
committer | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-08-31 14:18:42 -0400 |
commit | f41c549e109e16a6400eb93ca6cac2ef1ce1ce5d (patch) | |
tree | 0ac38c70827671862553d37dcac6b86f95ed2f8b | |
parent | 7b126b0eb8fc8bdab7e5c12c28d0ed58a48505bb (diff) | |
download | mongo-f41c549e109e16a6400eb93ca6cac2ef1ce1ce5d.tar.gz |
SERVER-25740 Prevent creation of views if featureCompatibilityVersion is 3.2
-rw-r--r-- | buildscripts/resmokeconfig/suites/views.yml | 1 | ||||
-rw-r--r-- | buildscripts/resmokeconfig/suites/views_rs.yml | 1 | ||||
-rw-r--r-- | jstests/views/durable_view_catalog.js | 3 | ||||
-rw-r--r-- | jstests/views/initial_sync_views.js | 3 | ||||
-rw-r--r-- | jstests/views/views_feature_compatibility_version.js | 89 | ||||
-rw-r--r-- | jstests/views/views_legacy.js | 2 | ||||
-rw-r--r-- | jstests/views/views_sharded.js | 6 | ||||
-rw-r--r-- | src/mongo/db/catalog/database.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.h | 6 | ||||
-rw-r--r-- | src/mongo/db/op_observer.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/views/durable_view_catalog.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/views/durable_view_catalog.h | 9 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog.cpp | 22 |
14 files changed, 140 insertions, 24 deletions
diff --git a/buildscripts/resmokeconfig/suites/views.yml b/buildscripts/resmokeconfig/suites/views.yml index 2b825ba753b..9a497f0b7ca 100644 --- a/buildscripts/resmokeconfig/suites/views.yml +++ b/buildscripts/resmokeconfig/suites/views.yml @@ -17,4 +17,3 @@ executor: mongod_options: set_parameters: enableTestCommands: 1 - enableViews: 1 diff --git a/buildscripts/resmokeconfig/suites/views_rs.yml b/buildscripts/resmokeconfig/suites/views_rs.yml index a4cacd25572..b29d8dc66df 100644 --- a/buildscripts/resmokeconfig/suites/views_rs.yml +++ b/buildscripts/resmokeconfig/suites/views_rs.yml @@ -23,5 +23,4 @@ executor: oplogSize: 511 set_parameters: enableTestCommands: 1 - enableViews: 1 num_nodes: 2 diff --git a/jstests/views/durable_view_catalog.js b/jstests/views/durable_view_catalog.js index c37255d7af9..5c06cf31167 100644 --- a/jstests/views/durable_view_catalog.js +++ b/jstests/views/durable_view_catalog.js @@ -12,8 +12,7 @@ let dbpath = MongoRunner.dataPath + '_durable_view_catalog'; resetDbpath(dbpath); - let mongodArgs = - {dbpath: dbpath, noCleanData: true, journal: '', setParameter: "enableViews=1"}; + let mongodArgs = {dbpath: dbpath, noCleanData: true, journal: ''}; // Start a mongod. let conn = MongoRunner.runMongod(mongodArgs); diff --git a/jstests/views/initial_sync_views.js b/jstests/views/initial_sync_views.js index e5b0ffdae1f..d6557cb5805 100644 --- a/jstests/views/initial_sync_views.js +++ b/jstests/views/initial_sync_views.js @@ -10,8 +10,7 @@ let testName = "initial_sync_views"; let hostName = getHostName(); - let replTest = - new ReplSetTest({name: testName, nodes: 1, nodeOptions: {setParameter: "enableViews=1"}}); + let replTest = new ReplSetTest({name: testName, nodes: 1}); replTest.startSet(); replTest.initiate(); diff --git a/jstests/views/views_feature_compatibility_version.js b/jstests/views/views_feature_compatibility_version.js new file mode 100644 index 00000000000..4e3d5ecb252 --- /dev/null +++ b/jstests/views/views_feature_compatibility_version.js @@ -0,0 +1,89 @@ +// Test that views are only enabled if featureCompatibilityVersion is 3.4. + +(function() { + "use strict"; + + const conn = MongoRunner.runMongod({}); + assert.neq(null, conn, "mongod was unable to start up"); + + const viewsDB = conn.getDB("views_feature_compatibility_version"); + assert.commandWorked(viewsDB.dropDatabase()); + assert.commandWorked(viewsDB.runCommand({create: "collection"})); + assert.commandWorked(viewsDB.runCommand({create: "collection2"})); + + const adminDB = conn.getDB("admin"); + + // Ensure the featureCompatibilityVersion is 3.4. + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + let res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq("3.4", res.featureCompatibilityVersion); + + // We can create a view when the featureCompatibilityVersion is 3.4. + assert.commandWorked(viewsDB.runCommand({create: "view", viewOn: "collection", pipeline: []})); + + // We can update a view when the featureCompatibilityVersion is 3.4. + assert.commandWorked(viewsDB.runCommand({collMod: "view", pipeline: []})); + + // We can perform inserts on the system.views collection when the featureCompatibilityVersion is + // 3.4. + assert.writeOK(viewsDB.system.views.insert( + {_id: "views_feature_compatibility_version.view2", viewOn: "collection", pipeline: []})); + + // We can perform updates on the system.views collection when the featureCompatibilityVersion is + // 3.4. + assert.writeOK(viewsDB.system.views.update({_id: "views_feature_compatibility_version.view2"}, + {$set: {viewOn: "collection2"}})); + + // We can perform deletes on the system.views collection when the featureCompatibilityVersion is + // 3.4. + assert.writeOK(viewsDB.system.views.remove({_id: "views_feature_compatibility_version.view2"})); + + // We cannot drop the system.views collection when the featureCompatibilityVersion is 3.4. + assert.throws(function() { + viewsDB.system.views.drop(); + }); + + // Ensure the featureCompatibilityVersion is 3.2. + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); + res = adminDB.runCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + assert.eq("3.2", res.featureCompatibilityVersion); + + // We cannot create views when the featureCompatibilityVersion is 3.2. + assert.commandFailed(viewsDB.runCommand({create: "view2", viewOn: "collection", pipeline: []})); + + // We cannot update views when the featureCompatibilityVersion is 3.2. + assert.commandFailed(viewsDB.runCommand({collMod: "view", pipeline: []})); + + // We can read from a view when the featureCompatibilityVersion is 3.2. + assert.writeOK(viewsDB.collection.insert({a: 5})); + assert.eq(5, viewsDB.view.findOne().a); + + // We cannot create a collection with the same name as a view when the + // featureCompatibilityVersion is 3.2. + assert.commandFailed(viewsDB.runCommand({create: "view"})); + assert.writeError(viewsDB.view.insert({a: 5})); + + // We cannot perform inserts on the system.views collection when the featureCompatibilityVersion + // is 3.2. + assert.writeError(viewsDB.system.views.insert( + {_id: "views_feature_compatibility_version.view2", viewOn: "collection", pipeline: []})); + + // We cannot perform updates on the system.views collection when the featureCompatibilityVersion + // is 3.2. + assert.writeError(viewsDB.system.views.update({_id: "views_feature_compatibility_version.view"}, + {$set: {viewOn: "collection2"}})); + + // We can drop a view namespace when the featureCompatibilityVersion is 3.2. + assert.eq(true, viewsDB.view.drop()); + + // We can perform deletes on the system.views collection when the featureCompatibilityVersion is + // 3.2. + assert.writeOK(viewsDB.system.views.remove({_id: "views_feature_compatibility_version.view"})); + + // We can drop the system.views collection when the featureCompatibilityVersion is 3.2. + assert.eq(true, viewsDB.system.views.drop()); + + MongoRunner.stopMongod(conn); +}()); diff --git a/jstests/views/views_legacy.js b/jstests/views/views_legacy.js index 46154fbdc30..bd31d5bb74e 100644 --- a/jstests/views/views_legacy.js +++ b/jstests/views/views_legacy.js @@ -8,7 +8,7 @@ (function() { "use strict"; - let conn = MongoRunner.runMongod({setParameter: "enableViews=1"}); + let conn = MongoRunner.runMongod({}); let viewsDB = conn.getDB("views_legacy"); assert.commandWorked(viewsDB.dropDatabase()); diff --git a/jstests/views/views_sharded.js b/jstests/views/views_sharded.js index 99408fcc9a3..42ca90c4ba3 100644 --- a/jstests/views/views_sharded.js +++ b/jstests/views/views_sharded.js @@ -8,11 +8,7 @@ (function() { "use strict"; - let st = new ShardingTest({ - name: "views_sharded", - shards: 2, - other: {shardOptions: {setParameter: "enableViews=1"}, enableBalancer: false} - }); + let st = new ShardingTest({name: "views_sharded", shards: 2, other: {enableBalancer: false}}); let mongos = st.s; let config = mongos.getDB("config"); diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index 41746be60ef..c9482569f73 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -387,6 +387,14 @@ Status Database::dropCollection(OperationContext* txn, StringData fullns) { if (_profile != 0) return Status(ErrorCodes::IllegalOperation, "turn off profiling before dropping system.profile collection"); + } else if (nss.isSystemDotViews()) { + if (serverGlobalParams.featureCompatibilityVersion.load() != + ServerGlobalParams::FeatureCompatibilityVersion_32) { + return Status(ErrorCodes::IllegalOperation, + "The featureCompatibilityVersion must be 3.2 to drop the " + "system.views collection. See " + "http://dochub.mongodb.org/core/3.4-feature-compatibility."); + } } else { return Status(ErrorCodes::IllegalOperation, "can't drop system ns"); } diff --git a/src/mongo/db/namespace_string.cpp b/src/mongo/db/namespace_string.cpp index 95d600fb27b..27495baa9d0 100644 --- a/src/mongo/db/namespace_string.cpp +++ b/src/mongo/db/namespace_string.cpp @@ -96,7 +96,7 @@ bool legalClientSystemNS(StringData ns) { if (ns.find(".system.js") != string::npos) return true; - if (nsToCollectionSubstring(ns) == "system.views") + if (nsToCollectionSubstring(ns) == NamespaceString::kSystemDotViewsCol) return true; return false; @@ -104,6 +104,7 @@ bool legalClientSystemNS(StringData ns) { const StringData NamespaceString::kAdminDb = "admin"_sd; const StringData NamespaceString::kLocalDb = "local"_sd; +constexpr StringData NamespaceString::kSystemDotViewsCol; const NamespaceString NamespaceString::kConfigCollectionNamespace(kConfigCollection); diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h index e4b3be50075..93810d6307b 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -63,6 +63,9 @@ public: // Namespace for the local database static const StringData kLocalDb; + // Name for the system views collection + static constexpr StringData kSystemDotViewsCol = "system.views"_sd; + // Namespace for storing configuration data, which needs to be replicated if the server is // running as a replica set. Documents in this collection should represent some configuration // state of the server, which needs to be recovered/consulted at startup. Each document in this @@ -162,6 +165,9 @@ public: bool isSystemDotProfile() const { return coll() == "system.profile"; } + bool isSystemDotViews() const { + return coll() == kSystemDotViewsCol; + } bool isConfigDB() const { return db() == "config"; } diff --git a/src/mongo/db/op_observer.cpp b/src/mongo/db/op_observer.cpp index 8defc1c71fe..f3e1a3729c8 100644 --- a/src/mongo/db/op_observer.cpp +++ b/src/mongo/db/op_observer.cpp @@ -91,6 +91,7 @@ void OpObserver::onInserts(OperationContext* txn, } if (nss.coll() == DurableViewCatalog::viewsCollectionName()) { DurableViewCatalog::onExternalChange(txn, nss); + DurableViewCatalog::confirm34FeatureCompatibilityVersion(); } } @@ -117,6 +118,7 @@ void OpObserver::onUpdate(OperationContext* txn, const OplogUpdateEntryArgs& arg NamespaceString nss(args.ns); if (nss.coll() == DurableViewCatalog::viewsCollectionName()) { DurableViewCatalog::onExternalChange(txn, nss); + DurableViewCatalog::confirm34FeatureCompatibilityVersion(); } if (args.ns == FeatureCompatibilityVersion::kCollection) { diff --git a/src/mongo/db/views/durable_view_catalog.cpp b/src/mongo/db/views/durable_view_catalog.cpp index ba84432b7cf..7f7648160df 100644 --- a/src/mongo/db/views/durable_view_catalog.cpp +++ b/src/mongo/db/views/durable_view_catalog.cpp @@ -59,6 +59,15 @@ void DurableViewCatalog::onExternalChange(OperationContext* txn, const Namespace } } +void DurableViewCatalog::confirm34FeatureCompatibilityVersion() { + uassert(40307, + "Cannot perform inserts or updates on system.views collection when " + "the featureCompatibilityVersion is 3.2. See " + "http://dochub.mongodb.org/core/3.4-feature-compatibility.", + serverGlobalParams.featureCompatibilityVersion.load() != + ServerGlobalParams::FeatureCompatibilityVersion_32); +} + // DurableViewCatalogImpl const std::string& DurableViewCatalogImpl::getName() const { diff --git a/src/mongo/db/views/durable_view_catalog.h b/src/mongo/db/views/durable_view_catalog.h index 1ea7268f2ee..3ca577cdfbb 100644 --- a/src/mongo/db/views/durable_view_catalog.h +++ b/src/mongo/db/views/durable_view_catalog.h @@ -32,13 +32,13 @@ #include "mongo/base/status.h" #include "mongo/base/string_data.h" +#include "mongo/db/namespace_string.h" #include "mongo/stdx/functional.h" namespace mongo { class BSONObj; class Database; -class NamespaceString; class OperationContext; /** @@ -49,7 +49,7 @@ class OperationContext; class DurableViewCatalog { public: static constexpr StringData viewsCollectionName() { - return "system.views"_sd; + return NamespaceString::kSystemDotViewsCol; } /** @@ -58,6 +58,11 @@ public: */ static void onExternalChange(OperationContext* txn, const NamespaceString& name); + /** + * Throws if featureCompatibilityVersion is 3.2. + */ + static void confirm34FeatureCompatibilityVersion(); + using Callback = stdx::function<void(const BSONObj& view)>; virtual Status iterate(OperationContext* txn, Callback callback) = 0; virtual void upsert(OperationContext* txn, diff --git a/src/mongo/db/views/view_catalog.cpp b/src/mongo/db/views/view_catalog.cpp index 9e4ad5c8b8f..6e8344059f9 100644 --- a/src/mongo/db/views/view_catalog.cpp +++ b/src/mongo/db/views/view_catalog.cpp @@ -47,15 +47,8 @@ #include "mongo/db/views/view.h" #include "mongo/util/log.h" -namespace { -bool enableViews = true; -} // namespace - namespace mongo { -ExportedServerParameter<bool, ServerParameterType::kStartupOnly> enableViewsParameter( - ServerParameterSet::getGlobal(), "enableViews", &enableViews); - Status ViewCatalog::reloadIfNeeded(OperationContext* txn) { stdx::lock_guard<stdx::mutex> lk(_mutex); return _reloadIfNeeded_inlock(txn); @@ -178,8 +171,12 @@ Status ViewCatalog::createView(OperationContext* txn, const BSONArray& pipeline) { stdx::lock_guard<stdx::mutex> lk(_mutex); - if (!enableViews) - return Status(ErrorCodes::CommandNotSupported, "View support not enabled"); + if (serverGlobalParams.featureCompatibilityVersion.load() == + ServerGlobalParams::FeatureCompatibilityVersion_32) { + return Status(ErrorCodes::CommandNotSupported, + "Cannot create view when the featureCompatibilityVersion is 3.2. See " + "http://dochub.mongodb.org/core/3.4-feature-compatibility."); + } if (viewName.db() != viewOn.db()) return Status(ErrorCodes::BadValue, @@ -201,6 +198,13 @@ Status ViewCatalog::modifyView(OperationContext* txn, const BSONArray& pipeline) { stdx::lock_guard<stdx::mutex> lk(_mutex); + if (serverGlobalParams.featureCompatibilityVersion.load() == + ServerGlobalParams::FeatureCompatibilityVersion_32) { + return Status(ErrorCodes::CommandNotSupported, + "Cannot modify view when the featureCompatibilityVersion is 3.2. See " + "http://dochub.mongodb.org/core/3.4-feature-compatibility."); + } + if (viewName.db() != viewOn.db()) return Status(ErrorCodes::BadValue, "View must be created on a view or collection in the same database"); |