From e7ecd039a519a29877a25f04de2cfa3437a422af Mon Sep 17 00:00:00 2001 From: Steven POST Date: Mon, 18 Mar 2024 18:24:04 +0100 Subject: [PATCH 01/10] Use server binary to get version The `mongosh` command we want to use as client has different versioning compared to the server, this used to be the same versioning when the old client was used. --- lib/facter/mongodb_version.rb | 6 +++--- spec/unit/mongodb_version_spec.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/facter/mongodb_version.rb b/lib/facter/mongodb_version.rb index 97fb1937b..a16a1602a 100644 --- a/lib/facter/mongodb_version.rb +++ b/lib/facter/mongodb_version.rb @@ -2,9 +2,9 @@ Facter.add(:mongodb_version) do setcode do - if Facter::Core::Execution.which('mongo') - mongodb_version = Facter::Core::Execution.execute('mongo --version 2>&1') - %r{MongoDB shell version:?\s+v?([\w.]+)}.match(mongodb_version)[1] + if Facter::Core::Execution.which('mongod') + mongodb_version = Facter::Core::Execution.execute('mongod --version 2>&1') + %r{^db version:?\s+v?([\w.]+)}.match(mongodb_version)[1] end end end diff --git a/spec/unit/mongodb_version_spec.rb b/spec/unit/mongodb_version_spec.rb index a7ede5d3d..688292067 100644 --- a/spec/unit/mongodb_version_spec.rb +++ b/spec/unit/mongodb_version_spec.rb @@ -10,12 +10,12 @@ describe 'mongodb_version' do context 'with value' do before do - allow(Facter::Core::Execution).to receive(:which).with('mongo').and_return(true) - allow(Facter::Core::Execution).to receive(:execute).with('mongo --version 2>&1').and_return('MongoDB shell version: 3.2.1') + allow(Facter::Core::Execution).to receive(:which).with('mongod').and_return(true) + allow(Facter::Core::Execution).to receive(:execute).with('mongod --version 2>&1').and_return('db version v5.0.6') end it { - expect(Facter.fact(:mongodb_version).value).to eq('3.2.1') + expect(Facter.fact(:mongodb_version).value).to eq('5.0.6') } end end From 320c82d53e7485a2038c0d6311032dab44e9cf79 Mon Sep 17 00:00:00 2001 From: Steven POST Date: Thu, 21 Mar 2024 18:06:52 +0100 Subject: [PATCH 02/10] Stop loading the /root/.mongorc.js when querying master state Querying master state doesn't require authentication. --- lib/facter/is_master.rb | 5 ++--- lib/puppet/provider/mongodb.rb | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/facter/is_master.rb b/lib/facter/is_master.rb index 40ce49e59..5b56a1ead 100644 --- a/lib/facter/is_master.rb +++ b/lib/facter/is_master.rb @@ -43,13 +43,12 @@ def get_options_from_config(file) file = mongod_conf_file if file options = get_options_from_config(file) - e = File.exist?('/root/.mongorc.js') ? 'load(\'/root/.mongorc.js\'); ' : '' # Check if the mongodb server is responding: - Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"#{e}printjson(db.adminCommand({ ping: 1 }))\"") + Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"printjson(db.adminCommand({ ping: 1 }))\"") if $CHILD_STATUS.success? - Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"#{e}db.isMaster().ismaster\"") + Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"db.isMaster().ismaster\"") else 'not_responding' end diff --git a/lib/puppet/provider/mongodb.rb b/lib/puppet/provider/mongodb.rb index c5944ac6c..81e4ed7d8 100644 --- a/lib/puppet/provider/mongodb.rb +++ b/lib/puppet/provider/mongodb.rb @@ -137,7 +137,6 @@ def self.conn_string def self.db_ismaster cmd_ismaster = 'db.isMaster().ismaster' - cmd_ismaster = mongorc_file + cmd_ismaster if mongorc_file db = 'admin' res = mongo_cmd(db, conn_string, cmd_ismaster).to_s.split(%r{\n}).last.chomp res.eql?('true') From 0a03dbf20f6063bd602afaf4630d8b3ef0cd76c6 Mon Sep 17 00:00:00 2001 From: Johan De Wit Date: Mon, 5 Jun 2023 17:53:44 +0200 Subject: [PATCH 03/10] Replace mongo shell with mongosh Needed changes: - Use stderr for errors instead of stdout. The `mongo` command from the older client package put its errors on stout and exited with zero as exit code. Mongosh, by contrast, puts errors on stderr instead of stdout and exits with a non-zero exit code. This means we need to pass the underlying exception to the caller so it can deal with it appropriately. - Replace old functions: - `printjson` has become `EJSON.stringify`. - `rs.secondaryOk()` and `rs.slaveOk()` have become `db.getMongo().setReadPref("primaryPreferred")`. - `db` is now an object instead of the database name, we need to call `getName()` on it to get the database name. - Don't throw an exception from the `if (authRequired()) {` block, as that causes the `mongosh` command to stop processing further commands and exit with a non-zero exit code. --- REFERENCE.md | 16 ++++-- lib/facter/is_master.rb | 6 +-- lib/puppet/provider/mongodb.rb | 24 ++++----- .../provider/mongodb_database/mongodb.rb | 4 +- lib/puppet/provider/mongodb_replset/mongo.rb | 51 ++++++++++--------- lib/puppet/provider/mongodb_shard/mongo.rb | 6 +-- lib/puppet/provider/mongodb_user/mongodb.rb | 7 ++- manifests/client.pp | 4 +- manifests/globals.pp | 5 ++ manifests/server.pp | 2 +- manifests/server/config.pp | 2 +- spec/acceptance/database_spec.rb | 8 +-- spec/acceptance/mongos_spec.rb | 2 +- spec/acceptance/replset_spec.rb | 20 ++++---- spec/acceptance/server_spec.rb | 14 ++--- spec/acceptance/sharding_spec.rb | 2 +- spec/acceptance/user_spec.rb | 30 +++++------ spec/classes/client_spec.rb | 2 +- spec/classes/server_spec.rb | 8 +-- .../provider/mongodb_database/mongodb_spec.rb | 2 +- .../provider/mongodb_replset/mongodb_spec.rb | 2 +- .../provider/mongodb_user/mongodb_spec.rb | 2 +- .../{mongorc.js.erb => mongoshrc.js.erb} | 25 ++++----- 23 files changed, 130 insertions(+), 114 deletions(-) rename templates/{mongorc.js.erb => mongoshrc.js.erb} (54%) diff --git a/REFERENCE.md b/REFERENCE.md index 2ecb99123..ea9fab493 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -64,7 +64,7 @@ Data type: `String[1]` Used to ensure that the package is installed, or that the package is absent/purged -Default value: `pick($mongodb::globals::version, 'present')` +Default value: `pick($mongodb::globals::client_version, 'present')` ##### `package_name` @@ -73,7 +73,7 @@ Data type: `String[1]` This setting can be used to specify the name of the package that should be installed. If not specified, the module will use whatever service name is the default for your OS distro. -Default value: `"mongodb-${mongodb::globals::edition}-shell"` +Default value: `'mongodb-mongosh'` ### `mongodb::globals` @@ -135,6 +135,7 @@ class {'mongodb::globals': The following parameters are available in the `mongodb::globals` class: * [`version`](#-mongodb--globals--version) +* [`client_version`](#-mongodb--globals--client_version) * [`manage_package_repo`](#-mongodb--globals--manage_package_repo) * [`repo_version`](#-mongodb--globals--repo_version) * [`use_enterprise_repo`](#-mongodb--globals--use_enterprise_repo) @@ -153,6 +154,15 @@ If not specified, the module will ensure packages with `present`. Default value: `undef` +##### `client_version` + +Data type: `Optional[String[1]]` + +The version of MongoDB Shell to install/manage. +If not specified, the module will ensure packages with `present`. + +Default value: `undef` + ##### `manage_package_repo` Data type: `Boolean` @@ -967,7 +977,7 @@ Data type: `String` The path to the custom mongosh rc file. -Default value: `"${facts['root_home']}/.mongorc.js"` +Default value: `"${facts['root_home']}/.mongoshrc.js"` ##### `service_manage` diff --git a/lib/facter/is_master.rb b/lib/facter/is_master.rb index 5b56a1ead..69f989c33 100644 --- a/lib/facter/is_master.rb +++ b/lib/facter/is_master.rb @@ -39,16 +39,16 @@ def get_options_from_config(file) Facter.add('mongodb_is_master') do setcode do - if %w[mongo mongod].all? { |m| Facter::Util::Resolution.which m } + if %w[mongosh mongod].all? { |m| Facter::Util::Resolution.which m } file = mongod_conf_file if file options = get_options_from_config(file) # Check if the mongodb server is responding: - Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"printjson(db.adminCommand({ ping: 1 }))\"") + Facter::Core::Execution.exec("mongosh --quiet #{options} --eval \"EJSON.stringify(db.adminCommand({ ping: 1 }))\"") if $CHILD_STATUS.success? - Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"db.isMaster().ismaster\"") + Facter::Core::Execution.exec("mongosh --quiet #{options} --eval \"db.isMaster().ismaster\"") else 'not_responding' end diff --git a/lib/puppet/provider/mongodb.rb b/lib/puppet/provider/mongodb.rb index 81e4ed7d8..b8f59cb2c 100644 --- a/lib/puppet/provider/mongodb.rb +++ b/lib/puppet/provider/mongodb.rb @@ -8,15 +8,15 @@ class Puppet::Provider::Mongodb < Puppet::Provider # Without initvars commands won't work. initvars - commands mongo: 'mongo' + commands mongosh: 'mongosh' # Optional defaults file - def self.mongorc_file - "load('#{Facter.value(:root_home)}/.mongorc.js'); " if File.file?("#{Facter.value(:root_home)}/.mongorc.js") + def self.mongoshrc_file + "load('#{Facter.value(:root_home)}/.mongoshrc.js'); " if File.file?("#{Facter.value(:root_home)}/.mongoshrc.js") end - def mongorc_file - self.class.mongorc_file + def mongoshrc_file + self.class.mongoshrc_file end def self.mongod_conf_file @@ -74,7 +74,7 @@ def self.tls_invalid_hostnames(config = nil) config['tlsallowInvalidHostnames'] end - def self.mongo_cmd(db, host, cmd) + def self.mongosh_cmd(db, host, cmd) config = mongo_conf args = [db, '--quiet', '--host', host] @@ -101,7 +101,7 @@ def self.mongo_cmd(db, host, cmd) end args += ['--eval', cmd] - mongo(args) + mongosh(args) end def self.conn_string @@ -138,7 +138,7 @@ def self.conn_string def self.db_ismaster cmd_ismaster = 'db.isMaster().ismaster' db = 'admin' - res = mongo_cmd(db, conn_string, cmd_ismaster).to_s.split(%r{\n}).last.chomp + res = mongosh_cmd(db, conn_string, cmd_ismaster).to_s.split(%r{\n}).last.chomp res.eql?('true') end @@ -155,14 +155,14 @@ def self.auth_enabled(config = nil) def self.mongo_eval(cmd, db = 'admin', retries = 10, host = nil) retry_count = retries retry_sleep = 3 - cmd = mongorc_file + cmd if mongorc_file + cmd = mongoshrc_file + cmd if mongoshrc_file out = nil begin out = if host - mongo_cmd(db, host, cmd) + mongosh_cmd(db, host, cmd) else - mongo_cmd(db, conn_string, cmd) + mongosh_cmd(db, conn_string, cmd) end rescue StandardError => e retry_count -= 1 @@ -173,7 +173,7 @@ def self.mongo_eval(cmd, db = 'admin', retries = 10, host = nil) end end - raise Puppet::ExecutionFailure, "Could not evaluate MongoDB shell command: #{cmd}" unless out + raise Puppet::ExecutionFailure, "Could not evaluate MongoDB shell command: #{cmd}, with: #{e.message}" unless out Puppet::Util::MongodbOutput.sanitize(out) end diff --git a/lib/puppet/provider/mongodb_database/mongodb.rb b/lib/puppet/provider/mongodb_database/mongodb.rb index 5dabe4365..a03cd6294 100644 --- a/lib/puppet/provider/mongodb_database/mongodb.rb +++ b/lib/puppet/provider/mongodb_database/mongodb.rb @@ -9,8 +9,8 @@ def self.instances require 'json' - pre_cmd = 'try { rs.secondaryOk() } catch (err) { rs.slaveOk() }' - dbs = JSON.parse mongo_eval("#{pre_cmd};printjson(db.getMongo().getDBs())") + pre_cmd = 'db.getMongo().setReadPref("primaryPreferred")' + dbs = JSON.parse mongo_eval("#{pre_cmd};EJSON.stringify(db.getMongo().getDBs())") dbs['databases'].map do |db| new(name: db['name'], diff --git a/lib/puppet/provider/mongodb_replset/mongo.rb b/lib/puppet/provider/mongodb_replset/mongo.rb index 7837533e2..98cc89404 100644 --- a/lib/puppet/provider/mongodb_replset/mongo.rb +++ b/lib/puppet/provider/mongodb_replset/mongo.rb @@ -153,31 +153,32 @@ def get_hosts_status(members) members.select do |member| host = member['host'] Puppet.debug "Checking replicaset member #{host} ..." - status = rs_status(host) - raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is not supposed to be part of a replicaset." if status.key?('errmsg') && status['errmsg'] == 'not running with --replSet' - - if auth_enabled && status.key?('errmsg') && (status['errmsg'].include?('unauthorized') || status['errmsg'].include?('not authorized') || status['errmsg'].include?('requires authentication')) - Puppet.warning "Host #{host} is available, but you are unauthorized because of authentication is enabled: #{auth_enabled}" - alive.push(member) - end - - if status.key?('errmsg') && status['errmsg'].include?('no replset config has been received') - Puppet.debug 'Mongo v4 rs.status() RS not initialized output' - alive.push(member) - end - - if status.key?('set') - raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is already part of another replicaset." if status['set'] != name - - # This node is alive and supposed to be a member of our set - Puppet.debug "Host #{host} is available for replset #{status['set']}" - alive.push(member) - elsif status.key?('info') - Puppet.debug "Host #{host} is alive but unconfigured: #{status['info']}" - alive.push(member) + begin + status = rs_status(host) + + if status.key?('set') + raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is already part of another replicaset." if status['set'] != name + + # This node is alive and supposed to be a member of our set + Puppet.debug "Host #{host} is available for replset #{status['set']}" + alive.push(member) + elsif status.key?('info') + Puppet.debug "Host #{host} is alive but unconfigured: #{status['info']}" + alive.push(member) + end + rescue Puppet::ExecutionFailure => e + raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is not supposed to be part of a replicaset." if e.message =~ %r{not running with --replSet} + + if auth_enabled && (e.message.include?('unauthorized') || e.message.include?('not authorized') || e.message.include?('requires authentication')) + Puppet.warning "Host #{host} is available, but you are unauthorized because of authentication is enabled: #{auth_enabled}" + alive.push(member) + elsif e.message.include?('no replset config has been received') + Puppet.debug 'Mongo v4 rs.status() RS not initialized output' + alive.push(member) + else + Puppet.warning "Can't connect to replicaset member #{host}." + end end - rescue Puppet::ExecutionFailure - Puppet.warning "Can't connect to replicaset member #{host}." end alive.uniq! dead = members - alive @@ -383,7 +384,7 @@ def mongo_command(command, host, retries = 4) def self.mongo_command(command, host = nil, retries = 4) begin - output = mongo_eval("printjson(#{command})", 'admin', retries, host) + output = mongo_eval("EJSON.stringify(#{command})", 'admin', retries, host) rescue Puppet::ExecutionFailure => e Puppet.debug "Got an exception: #{e}" raise diff --git a/lib/puppet/provider/mongodb_shard/mongo.rb b/lib/puppet/provider/mongodb_shard/mongo.rb index 283d6cce2..6347bf59b 100644 --- a/lib/puppet/provider/mongodb_shard/mongo.rb +++ b/lib/puppet/provider/mongodb_shard/mongo.rb @@ -13,7 +13,7 @@ mk_resource_methods - commands mongo: 'mongo' + commands mongosh: 'mongosh' def initialize(value = {}) super(value) @@ -152,8 +152,8 @@ def self.mongo_command(command, host = nil, _retries = 4) args = [] args << '--quiet' args << ['--host', host] if host - args << ['--eval', "printjson(#{command})"] - output = mongo(args.flatten) + args << ['--eval', "EJSON.stringify(#{command})"] + output = mongosh(args.flatten) rescue Puppet::ExecutionFailure => e raise unless e =~ %r{Error: couldn't connect to server} && wait <= (2**max_wait) diff --git a/lib/puppet/provider/mongodb_user/mongodb.rb b/lib/puppet/provider/mongodb_user/mongodb.rb index d9db0fa45..7eeb79eba 100644 --- a/lib/puppet/provider/mongodb_user/mongodb.rb +++ b/lib/puppet/provider/mongodb_user/mongodb.rb @@ -10,13 +10,12 @@ def self.instances require 'json' if db_ismaster - script = 'printjson(db.system.users.find().toArray())' + script = 'EJSON.stringify(db.system.users.find().toArray())' # A hack to prevent prefetching failures until admin user is created - script = "try {#{script}} catch (e) { if (e.message.match(/not authorized on admin/)) { 'not authorized on admin' } else {throw e}}" if auth_enabled + script = "try {#{script}} catch (e) { if (e.message.match(/requires authentication/) || e.message.match(/not authorized on admin/)) { 'not authorized on admin' } else {throw e}}" if auth_enabled out = mongo_eval(script) - - return [] if auth_enabled && out.include?('not authorized on admin') + return [] if auth_enabled && (out.include?('requires authentication') || out.include?('not authorized on admin')) users = JSON.parse out diff --git a/manifests/client.pp b/manifests/client.pp index a1160769c..903c243ec 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -11,8 +11,8 @@ # If not specified, the module will use whatever service name is the default for your OS distro. # class mongodb::client ( - String[1] $ensure = pick($mongodb::globals::version, 'present'), - String[1] $package_name = "mongodb-${mongodb::globals::edition}-shell", + String[1] $ensure = pick($mongodb::globals::client_version, 'present'), + String[1] $package_name = 'mongodb-mongosh', ) inherits mongodb::globals { package { 'mongodb_client': ensure => $ensure, diff --git a/manifests/globals.pp b/manifests/globals.pp index db0532b2d..5ffbdb91a 100644 --- a/manifests/globals.pp +++ b/manifests/globals.pp @@ -41,6 +41,10 @@ # The version of MonogDB to install/manage. # If not specified, the module will ensure packages with `present`. # +# @param client_version +# The version of MongoDB Shell to install/manage. +# If not specified, the module will ensure packages with `present`. +# # @param manage_package_repo # Whether to manage MongoDB software repository. # @@ -71,6 +75,7 @@ # class mongodb::globals ( Optional[String[1]] $version = undef, + Optional[String[1]] $client_version = undef, Boolean $manage_package_repo = true, String[1] $repo_version = '5.0', Boolean $use_enterprise_repo = false, diff --git a/manifests/server.pp b/manifests/server.pp index aabe3405a..17425fc74 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -328,7 +328,7 @@ Optional[Stdlib::Absolutepath] $pidfilepath = undef, String[4,4] $pidfilemode = '0644', Boolean $manage_pidfile = false, - String $rcfile = "${facts['root_home']}/.mongorc.js", + String $rcfile = "${facts['root_home']}/.mongoshrc.js", Boolean $service_manage = true, Optional[String[1]] $service_provider = undef, String[1] $service_name = 'mongod', diff --git a/manifests/server/config.pp b/manifests/server/config.pp index 399cb3607..8c4f0bdbb 100644 --- a/manifests/server/config.pp +++ b/manifests/server/config.pp @@ -177,7 +177,7 @@ if $handle_creds { file { $rcfile: ensure => file, - content => template('mongodb/mongorc.js.erb'), + content => template('mongodb/mongoshrc.js.erb'), owner => 'root', group => 'root', mode => '0600', diff --git a/spec/acceptance/database_spec.rb b/spec/acceptance/database_spec.rb index 49051ea05..68d624d38 100644 --- a/spec/acceptance/database_spec.rb +++ b/spec/acceptance/database_spec.rb @@ -29,8 +29,8 @@ class { 'mongodb::globals': end it 'creates the databases' do - shell("mongo testdb1 --eval 'printjson(db.getMongo().getDBs())'") - shell("mongo testdb2 --eval 'printjson(db.getMongo().getDBs())'") + shell("mongosh testdb1 --eval 'EJSON.stringify(db.getMongo().getDBs())'") + shell("mongosh testdb2 --eval 'EJSON.stringify(db.getMongo().getDBs())'") end end @@ -59,8 +59,8 @@ class { 'mongodb::globals': end it 'creates the database' do - shell("mongo testdb1 --port 27018 --eval 'printjson(db.getMongo().getDBs())'") - shell("mongo testdb2 --port 27018 --eval 'printjson(db.getMongo().getDBs())'") + shell("mongosh testdb1 --port 27018 --eval 'EJSON.stringify(db.getMongo().getDBs())'") + shell("mongosh testdb2 --port 27018 --eval 'EJSON.stringify(db.getMongo().getDBs())'") end end end diff --git a/spec/acceptance/mongos_spec.rb b/spec/acceptance/mongos_spec.rb index 1b4a81c81..676a7924b 100644 --- a/spec/acceptance/mongos_spec.rb +++ b/spec/acceptance/mongos_spec.rb @@ -52,7 +52,7 @@ class { 'mongodb::globals': it { is_expected.to be_listening } end - describe command('mongo --version') do + describe command('mongod --version') do its(:exit_status) { is_expected.to eq 0 } end end diff --git a/spec/acceptance/replset_spec.rb b/spec/acceptance/replset_spec.rb index 2b04bd69a..222aff1ad 100644 --- a/spec/acceptance/replset_spec.rb +++ b/spec/acceptance/replset_spec.rb @@ -9,7 +9,7 @@ describe 'mongodb_replset resource' do after :all do # Have to drop the DB to disable replsets for further testing - on hosts, %{mongo local --verbose --eval 'db.dropDatabase()'} + on hosts, %{mongosh local --verbose --eval 'db.dropDatabase()'} pp = <<-EOS class { 'mongodb::globals': @@ -55,7 +55,7 @@ class { 'mongodb::client': } } EOS apply_manifest_on(hosts_as('master'), pp, catch_failures: true) - on(hosts_as('master'), 'mongo --quiet --eval "printjson(rs.conf())"') do |r| + on(hosts_as('master'), 'mongosh --quiet --eval "EJSON.stringify(rs.conf())"') do |r| expect(r.stdout).to match %r{#{hosts[0]}:27017} expect(r.stdout).to match %r{#{hosts[1]}:27017} end @@ -63,18 +63,18 @@ class { 'mongodb::client': } it 'inserts data on the master' do sleep(30) - on hosts_as('master'), %{mongo --verbose --eval 'db.test.save({name:"test1",value:"some value"})'} + on hosts_as('master'), %{mongosh --verbose --eval 'db.test.save({name:"test1",value:"some value"})'} end it 'checks the data on the master' do - on hosts_as('master'), %{mongo --verbose --eval 'printjson(db.test.findOne({name:"test1"}))'} do |r| + on hosts_as('master'), %{mongosh --verbose --eval 'EJSON.stringify(db.test.findOne({name:"test1"}))'} do |r| expect(r.stdout).to match %r{some value} end end it 'checks the data on the slave' do sleep(10) - on hosts_as('slave'), %{mongo --verbose --eval 'try { rs.secondaryOk() } catch (err) { rs.slaveOk() }; printjson(db.test.findOne({name:"test1"}))'} do |r| + on hosts_as('slave'), %{mongosh --verbose --eval 'db.getMongo().setReadPref("primaryPreferred"); EJSON.stringify(db.test.findOne({name:"test1"}))'} do |r| expect(r.stdout).to match %r{some value} end end @@ -83,7 +83,7 @@ class { 'mongodb::client': } describe 'mongodb_replset resource with auth => true' do after :all do # Have to drop the DB to disable replsets for further testing - on hosts, %{mongo local --verbose --eval 'db.dropDatabase()'} + on hosts, %{mongosh local --verbose --eval 'db.dropDatabase()'} pp = <<-EOS class { 'mongodb::globals': @@ -152,7 +152,7 @@ class { 'mongodb::server': EOS apply_manifest_on(hosts_as('master'), pp, catch_failures: true) apply_manifest_on(hosts_as('master'), pp, catch_changes: true) - on(hosts_as('master'), 'mongo --quiet --eval "load(\'/root/.mongorc.js\');printjson(rs.conf())"') do |r| + on(hosts_as('master'), 'mongosh --quiet --eval "load(\'/root/.mongoshrc.js\');EJSON.stringify(rs.conf())"') do |r| expect(r.stdout).to match %r{#{hosts[0]}:27017} expect(r.stdout).to match %r{#{hosts[1]}:27017} end @@ -160,18 +160,18 @@ class { 'mongodb::server': it 'inserts data on the master' do sleep(30) - on hosts_as('master'), %{mongo test --verbose --eval 'load("/root/.mongorc.js");db.dummyData.insert({"created_by_puppet": 1})'} + on hosts_as('master'), %{mongosh test --verbose --eval 'load("/root/.mongoshrc.js");db.dummyData.insert({"created_by_puppet": 1})'} end it 'checks the data on the master' do - on hosts_as('master'), %{mongo test --verbose --eval 'load("/root/.mongorc.js");printjson(db.dummyData.findOne())'} do |r| + on hosts_as('master'), %{mongosh test --verbose --eval 'load("/root/.mongoshrc.js");EJSON.stringify(db.dummyData.findOne())'} do |r| expect(r.stdout).to match %r{created_by_puppet} end end it 'checks the data on the slave' do sleep(10) - on hosts_as('slave'), %{mongo test --verbose --eval 'load("/root/.mongorc.js");try { rs.secondaryOk() } catch (err) { rs.slaveOk() };printjson(db.dummyData.findOne())'} do |r| + on hosts_as('slave'), %{mongosh test --verbose --eval 'load("/root/.mongoshrc.js");db.getMongo().setReadPref("primaryPreferred");EJSON.stringify(db.dummyData.findOne())'} do |r| expect(r.stdout).to match %r{created_by_puppet} end end diff --git a/spec/acceptance/server_spec.rb b/spec/acceptance/server_spec.rb index a13af2314..0864a3e7f 100644 --- a/spec/acceptance/server_spec.rb +++ b/spec/acceptance/server_spec.rb @@ -41,7 +41,7 @@ class { 'mongodb::globals': it { is_expected.to be_listening } end - describe command('mongo --version') do + describe command('mongod --version') do its(:exit_status) { is_expected.to eq 0 } end end @@ -132,11 +132,11 @@ class { 'mongodb::globals': it { is_expected.to be_listening } end - describe command('mongo --quiet --eval "db.serverCmdLineOpts().code"') do - its(:stdout) { is_expected.to match '13' } + describe command('mongosh --quiet --eval "db.serverCmdLineOpts().ok"') do + its(:stderr) { is_expected.to match %r{requires authentication} } end - describe file('/root/.mongorc.js') do + describe file('/root/.mongoshrc.js') do it { is_expected.to be_file } it { is_expected.to be_owned_by 'root' } it { is_expected.to be_grouped_into 'root' } @@ -144,12 +144,12 @@ class { 'mongodb::globals': it { is_expected.to contain 'db.auth(\'admin\', \'password\')' } end - describe command("mongo admin --quiet --eval \"load('/root/.mongorc.js');printjson(db.getUser('admin')['customData'])\"") do + describe command("mongosh admin --quiet --eval \"load('/root/.mongoshrc.js');EJSON.stringify(db.getUser('admin')['customData'])\"") do its(:exit_status) { is_expected.to eq 0 } - its(:stdout) { is_expected.to match "{ \"createdBy\" : \"Puppet Mongodb_user['User admin on db admin']\" }\n" } + its(:stdout) { is_expected.to match "{\"createdBy\":\"Puppet Mongodb_user['User admin on db admin']\"}\n" } end - describe command('mongo --version') do + describe command('mongod --version') do its(:exit_status) { is_expected.to eq 0 } end end diff --git a/spec/acceptance/sharding_spec.rb b/spec/acceptance/sharding_spec.rb index 88f755c51..2c826234a 100644 --- a/spec/acceptance/sharding_spec.rb +++ b/spec/acceptance/sharding_spec.rb @@ -53,7 +53,7 @@ class { 'mongodb::client': } EOS apply_manifest_on(hosts_as('router'), pp, catch_failures: true) - on(hosts_as('router'), 'mongo --quiet --eval "printjson(sh.status())"') do |r| + on(hosts_as('router'), 'mongosh --quiet --eval "EJSON.stringify(sh.status())"') do |r| expect(r.stdout).to match %r{foo/shard:27018} expect(r.stdout).to match %r{foo\.toto} end diff --git a/spec/acceptance/user_spec.rb b/spec/acceptance/user_spec.rb index 2df50313e..fc042dd14 100644 --- a/spec/acceptance/user_spec.rb +++ b/spec/acceptance/user_spec.rb @@ -28,8 +28,8 @@ class { 'mongodb::globals': end it 'creates the user' do - shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| - expect(r.stdout.chomp).to eq('1') + shell("mongosh testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| + expect(r.stdout.chomp).to eq('{ ok: 1 }') end end @@ -54,9 +54,9 @@ class { 'mongodb::globals': end it 'auth should fail' do - shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| - expect(r.stdout.chomp).to contain('Error: Authentication failed') - end + auth_result = shell("mongosh testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'", acceptable_exit_codes: [1]) + expect(auth_result.exit_code).to eq 1 + expect(auth_result.stderr).to match %r{MongoServerError: Authentication failed} end end @@ -82,8 +82,8 @@ class { 'mongodb::globals': end it 'creates the user' do - shell("mongo testdb --quiet --port 27018 --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| - expect(r.stdout.chomp).to eq('1') + shell("mongosh testdb --quiet --port 27018 --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| + expect(r.stdout.chomp).to eq('{ ok: 1 }') end end end @@ -111,8 +111,8 @@ class { 'mongodb::globals': end it 'creates the user' do - shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| - expect(r.stdout.chomp).to eq('1') + shell("mongosh testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| + expect(r.stdout.chomp).to eq('{ ok: 1 }') end end end @@ -148,25 +148,25 @@ class { 'mongodb::globals': end it 'allows the testuser' do - shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| - expect(r.stdout.chomp).to eq('1') + shell("mongosh testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\")'") do |r| + expect(r.stdout.chomp).to eq('{ ok: 1 }') end end it 'assigns roles to testuser' do - shell("mongo testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\"); db.getUser(\"testuser\")[\"roles\"].forEach(function(role){print(role.role + \"@\" + role.db)})'") do |r| + shell("mongosh testdb --quiet --eval 'db.auth(\"testuser\",\"passw0rd\"); db.getUser(\"testuser\")[\"roles\"].forEach(function(role){print(role.role + \"@\" + role.db)})'") do |r| expect(r.stdout.split(%r{\n})).to contain_exactly('readWrite@testdb', 'dbAdmin@testdb') end end it 'allows the second user to connect to its default database' do - shell("mongo testdb2 --quiet --eval 'db.auth(\"testuser2\",\"passw0rd\")'") do |r| - expect(r.stdout.chomp).to eq('1') + shell("mongosh testdb2 --quiet --eval 'db.auth(\"testuser2\",\"passw0rd\")'") do |r| + expect(r.stdout.chomp).to eq('{ ok: 1 }') end end it 'assigns roles to testuser2' do - shell("mongo testdb2 --quiet --eval 'db.auth(\"testuser2\",\"passw0rd\"); db.getUser(\"testuser2\")[\"roles\"].forEach(function(role){print(role.role + \"@\" + role.db)})'") do |r| + shell("mongosh testdb2 --quiet --eval 'db.auth(\"testuser2\",\"passw0rd\"); db.getUser(\"testuser2\")[\"roles\"].forEach(function(role){print(role.role + \"@\" + role.db)})'") do |r| expect(r.stdout.split(%r{\n})).to contain_exactly('readWrite@testdb2', 'dbAdmin@testdb2', 'readWrite@testdb', 'dbAdmin@testdb') end end diff --git a/spec/classes/client_spec.rb b/spec/classes/client_spec.rb index c8574b05c..09381ba3b 100644 --- a/spec/classes/client_spec.rb +++ b/spec/classes/client_spec.rb @@ -9,7 +9,7 @@ context 'with defaults' do it { is_expected.to compile.with_all_deps } - it { is_expected.to create_package('mongodb_client').with_ensure('present').with_name('mongodb-org-shell').with_tag('mongodb_package') } + it { is_expected.to create_package('mongodb_client').with_ensure('present').with_name('mongodb-mongosh').with_tag('mongodb_package') } end context 'with manage_package_repo set to false' do diff --git a/spec/classes/server_spec.rb b/spec/classes/server_spec.rb index 5567b3ddc..9dc3a89a7 100644 --- a/spec/classes/server_spec.rb +++ b/spec/classes/server_spec.rb @@ -49,7 +49,7 @@ it { is_expected.to contain_class('mongodb::repo') } it { is_expected.not_to contain_file(config_file).with_content(%r{fork}) } - it { is_expected.to contain_file('/root/.mongorc.js').with_ensure('file').without_content(%r{db\.auth}) } + it { is_expected.to contain_file('/root/.mongoshrc.js').with_ensure('file').without_content(%r{db\.auth}) } it { is_expected.not_to contain_exec('fix dbpath permissions') } end @@ -167,7 +167,7 @@ end it { is_expected.to contain_file(config_file).with_content(%r{^security\.authorization: enabled$}) } - it { is_expected.to contain_file('/root/.mongorc.js') } + it { is_expected.to contain_file('/root/.mongoshrc.js') } end describe 'when specifying set_parameter array value' do @@ -252,7 +252,7 @@ end it { - is_expected.to contain_file('/root/.mongorc.js'). + is_expected.to contain_file('/root/.mongoshrc.js'). with_ensure('file'). with_owner('root'). with_group('root'). @@ -268,7 +268,7 @@ } end - it { is_expected.to contain_file('/root/.mongorc.js').with_ensure('file').without_content(%r{db\.auth}) } + it { is_expected.to contain_file('/root/.mongoshrc.js').with_ensure('file').without_content(%r{db\.auth}) } end end diff --git a/spec/unit/puppet/provider/mongodb_database/mongodb_spec.rb b/spec/unit/puppet/provider/mongodb_database/mongodb_spec.rb index c783d6898..8f25fb384 100644 --- a/spec/unit/puppet/provider/mongodb_database/mongodb_spec.rb +++ b/spec/unit/puppet/provider/mongodb_database/mongodb_spec.rb @@ -38,7 +38,7 @@ tmp = Tempfile.new('test') mongodconffile = tmp.path allow(provider.class).to receive(:mongod_conf_file).and_return(mongodconffile) - allow(provider.class).to receive(:mongo_eval).with('try { rs.secondaryOk() } catch (err) { rs.slaveOk() };printjson(db.getMongo().getDBs())').and_return(raw_dbs) + allow(provider.class).to receive(:mongo_eval).with('db.getMongo().setReadPref("primaryPreferred");EJSON.stringify(db.getMongo().getDBs())').and_return(raw_dbs) allow(provider.class).to receive(:db_ismaster).and_return(true) end diff --git a/spec/unit/puppet/provider/mongodb_replset/mongodb_spec.rb b/spec/unit/puppet/provider/mongodb_replset/mongodb_spec.rb index 1a7872845..2b6b2c825 100644 --- a/spec/unit/puppet/provider/mongodb_replset/mongodb_spec.rb +++ b/spec/unit/puppet/provider/mongodb_replset/mongodb_spec.rb @@ -166,7 +166,7 @@ end it 'raises an error when at least one member is not running with --replSet' do - allow(provider).to receive(:rs_status).and_return('ok' => 0, 'errmsg' => 'not running with --replSet') + allow(provider).to receive(:rs_status).and_raise(Puppet::ExecutionFailure, 'MongoServerError: not running with --replSet') provider.members = valid_members expect { provider.flush }.to raise_error(Puppet::Error, %r{is not supposed to be part of a replicaset\.$}) end diff --git a/spec/unit/puppet/provider/mongodb_user/mongodb_spec.rb b/spec/unit/puppet/provider/mongodb_user/mongodb_spec.rb index 9f77872f0..7f74adf5d 100644 --- a/spec/unit/puppet/provider/mongodb_user/mongodb_spec.rb +++ b/spec/unit/puppet/provider/mongodb_user/mongodb_spec.rb @@ -59,7 +59,7 @@ tmp = Tempfile.new('test') mongodconffile = tmp.path allow(provider.class).to receive(:mongod_conf_file).and_return(mongodconffile) - allow(provider.class).to receive(:mongo_eval).with('printjson(db.system.users.find().toArray())').and_return(raw_users) + allow(provider.class).to receive(:mongo_eval).with('EJSON.stringify(db.system.users.find().toArray())').and_return(raw_users) allow(provider.class).to receive(:mongo_version).and_return('4.4.0') allow(provider.class).to receive(:db_ismaster).and_return(true) end diff --git a/templates/mongorc.js.erb b/templates/mongoshrc.js.erb similarity index 54% rename from templates/mongorc.js.erb rename to templates/mongoshrc.js.erb index 9e060306f..8cf68f0fa 100644 --- a/templates/mongorc.js.erb +++ b/templates/mongoshrc.js.erb @@ -19,31 +19,32 @@ function rsReconfigSettings(settings){ <% if @auth and @store_creds -%> function authRequired() { try { - return db.serverCmdLineOpts().code == 13; + return db.serverCmdLineOpts().ok != 1; } catch (err) { - return false; + if (err.message.match(/requires authentication/) || err.message.match(/not authorized on admin/)) { + return true + } else { + throw("Unknown error :" + err) + } } } if (authRequired()) { <%- if @replset -%> - // rs.slaveOk has been deprecated, use secondaryOk if available - try { - rs.secondaryOk() - } - catch (err) { - rs.slaveOk() - } + db.getMongo().setReadPref('primaryPreferred') <%- end -%> try { - var prev_db = db + var prev_db = db.getName() db = db.getSiblingDB('admin') db.auth('<%= @admin_username %>', '<%= @admin_password_unsensitive %>') db = db.getSiblingDB(prev_db) } catch (err) { - // This isn't catching authentication errors as I'd expect... - abort('Unknown error') + // Silently ignore this error, we can't really do anything about it. + // If authentication fails here, that can mean 2 things: + // - Some error or corruption + // - Authentication is required, but no user is set up yet. + // This is normal when setting up a new cluster/server. } } <% end -%> From a3fc5336a33db43f60b08fc9e733469c4f9eec4a Mon Sep 17 00:00:00 2001 From: Steven POST Date: Tue, 26 Mar 2024 14:06:55 +0100 Subject: [PATCH 04/10] Connect to localhost in provider when possible The provider previously used the external IP to connect instead of the loopback. When using the loopback, the option `enableLocalhostAuthBypass` (true by default) allows to bypass authentication when a user doesn't yet exists. Which is exactly what would prevent us from executing administrative tasks (like setting up the replicaset) when auth is enabled, but not yet set up. We can only connect to localhost when MongoDB is listening on either the 'bind all' address (0.0.0.0 or ::0) or the local loopback address (127.0.0.1 or ::1). --- lib/puppet/provider/mongodb.rb | 8 ++++++-- lib/puppet/provider/mongodb_replset/mongo.rb | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/puppet/provider/mongodb.rb b/lib/puppet/provider/mongodb.rb index b8f59cb2c..1c01cc5c1 100644 --- a/lib/puppet/provider/mongodb.rb +++ b/lib/puppet/provider/mongodb.rb @@ -111,9 +111,9 @@ def self.conn_string first_ip_in_list = bindip.split(',').first ip_real = case first_ip_in_list when '0.0.0.0' - Facter.value(:fqdn) + '127.0.0.1' when %r{\[?::0\]?} - Facter.value(:fqdn) + '::1' else first_ip_in_list end @@ -135,6 +135,10 @@ def self.conn_string "#{ip_real}:#{port_real}" end + def conn_string + self.class.conn_string + end + def self.db_ismaster cmd_ismaster = 'db.isMaster().ismaster' db = 'admin' diff --git a/lib/puppet/provider/mongodb_replset/mongo.rb b/lib/puppet/provider/mongodb_replset/mongo.rb index 98cc89404..3013da5e4 100644 --- a/lib/puppet/provider/mongodb_replset/mongo.rb +++ b/lib/puppet/provider/mongodb_replset/mongo.rb @@ -154,7 +154,11 @@ def get_hosts_status(members) host = member['host'] Puppet.debug "Checking replicaset member #{host} ..." begin - status = rs_status(host) + status = if host.split(':').first == Facter.value(:fqdn) + rs_status(conn_string) + else + rs_status(host) + end if status.key?('set') raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is already part of another replicaset." if status['set'] != name From d6284478a7817a1e4106094c8706c781954f2fa6 Mon Sep 17 00:00:00 2001 From: Steven POST Date: Tue, 26 Mar 2024 15:11:38 +0100 Subject: [PATCH 05/10] Use a more suitable method of detecting if authentication is needed The `db.serverCmdLineOpts()` method always requires authentication when auth is enabled. It doesn't take the `enableLocalAuthBypass` parameter into account, the subsequent authentication attempt always fails if a user doesn't exists. This commit switches to the `rs.status()` method, as that method does take the `enableLocalAuthBypass` parameter into account and allows us to obtain a shell before with authentication enabled, but before the user exists. --- templates/mongoshrc.js.erb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/templates/mongoshrc.js.erb b/templates/mongoshrc.js.erb index 8cf68f0fa..c15c52c30 100644 --- a/templates/mongoshrc.js.erb +++ b/templates/mongoshrc.js.erb @@ -19,13 +19,15 @@ function rsReconfigSettings(settings){ <% if @auth and @store_creds -%> function authRequired() { try { - return db.serverCmdLineOpts().ok != 1; + return rs.status().ok != 1; } catch (err) { if (err.message.match(/requires authentication/) || err.message.match(/not authorized on admin/)) { return true - } else { - throw("Unknown error :" + err) + if (err.message.match(/not running with --replSet/)) { + return false } + throw("Unknown error :" + err) + } } } From 4d6b3b0d8193038d8a4dd724a8896065d9815480 Mon Sep 17 00:00:00 2001 From: Steven POST Date: Tue, 26 Mar 2024 16:56:43 +0100 Subject: [PATCH 06/10] Replace deprecated command with newer alternative > Deprecated mongosh Method > This method is deprecated in mongosh. For alternative methods, see > Compatibility Changes with Legacy mongo Shell. > https://www.mongodb.com/docs/mongodb-shell/reference/compatibility/#std-label-compatibility See https://www.mongodb.com/docs/manual/reference/method/db.collection.insert/ --- lib/puppet/provider/mongodb_database/mongodb.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/provider/mongodb_database/mongodb.rb b/lib/puppet/provider/mongodb_database/mongodb.rb index a03cd6294..1cf061d25 100644 --- a/lib/puppet/provider/mongodb_database/mongodb.rb +++ b/lib/puppet/provider/mongodb_database/mongodb.rb @@ -29,7 +29,7 @@ def self.prefetch(resources) def create if db_ismaster - out = mongo_eval('db.dummyData.insert({"created_by_puppet": 1})', @resource[:name]) + out = mongo_eval('db.dummyData.insertOne({"created_by_puppet": 1})', @resource[:name]) raise "Failed to create DB '#{@resource[:name]}'\n#{out}" if %r{writeError} =~ out else Puppet.warning 'Database creation is available only from master host' From 18ed042c0fbddf3e6ecf81bebcdf4ee6bd6aeefa Mon Sep 17 00:00:00 2001 From: Steven POST Date: Wed, 27 Mar 2024 09:07:37 +0100 Subject: [PATCH 07/10] Users should be created before the database Databases in MongoDB are created lazy, meaning there is no `create` command. Thus if a record is inserted the DB is created. When auth is enabled, any attempt to insert data is denied because of missing auth. However the `db.createUser()` function works because of the config option `enableBypassLocalAuth`. For an overview see https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set-with-keyfile-access-control/ --- lib/puppet/type/mongodb_user.rb | 2 +- spec/acceptance/user_spec.rb | 30 ++++++++++++++++++------------ spec/defines/db_spec.rb | 4 ++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/puppet/type/mongodb_user.rb b/lib/puppet/type/mongodb_user.rb index 592075407..b8e28ef1b 100644 --- a/lib/puppet/type/mongodb_user.rb +++ b/lib/puppet/type/mongodb_user.rb @@ -117,7 +117,7 @@ def insync?(_is) %w[mongodb mongod] end - autorequire(:mongodb_database) do + autobefore(:mongodb_database) do self[:database] end diff --git a/spec/acceptance/user_spec.rb b/spec/acceptance/user_spec.rb index fc042dd14..6bb1d03ff 100644 --- a/spec/acceptance/user_spec.rb +++ b/spec/acceptance/user_spec.rb @@ -14,8 +14,9 @@ class { 'mongodb::globals': } -> class { 'mongodb::server': } -> class { 'mongodb::client': } - -> mongodb_database { 'testdb': ensure => present } - -> + + mongodb_database { 'testdb': ensure => present } + mongodb_user {'testuser': ensure => present, password_hash => mongodb_password('testuser', 'passw0rd'), @@ -40,8 +41,9 @@ class { 'mongodb::globals': } -> class { 'mongodb::server': } -> class { 'mongodb::client': } - -> mongodb_database { 'testdb': ensure => present } - -> + + mongodb_database { 'testdb': ensure => present } + mongodb_user {'testuser': ensure => absent, password_hash => mongodb_password('testuser', 'passw0rd'), @@ -68,8 +70,9 @@ class { 'mongodb::globals': } -> class { 'mongodb::server': port => 27018 } -> class { 'mongodb::client': } - -> mongodb_database { 'testdb': ensure => present } - -> + + mongodb_database { 'testdb': ensure => present } + mongodb_user {'testuser': ensure => present, password_hash => mongodb_password('testuser', 'passw0rd'), @@ -96,8 +99,9 @@ class { 'mongodb::globals': } -> class { 'mongodb::server': } -> class { 'mongodb::client': } - -> mongodb_database { 'testdb': ensure => present } - -> + + mongodb_database { 'testdb': ensure => present } + mongodb_user {'testuser': ensure => present, password_hash => mongodb_password('testuser', 'passw0rd'), @@ -125,16 +129,18 @@ class { 'mongodb::globals': } -> class { 'mongodb::server': } -> class { 'mongodb::client': } - -> mongodb_database { 'testdb': ensure => present } - -> mongodb_database { 'testdb2': ensure => present } - -> + + mongodb_database { 'testdb': ensure => present } + + mongodb_database { 'testdb2': ensure => present } + mongodb_user {'testuser': ensure => present, password_hash => mongodb_password('testuser', 'passw0rd'), database => 'testdb', roles => ['readWrite', 'dbAdmin'], } - -> + mongodb_user {'testuser2': ensure => present, password_hash => mongodb_password('testuser2', 'passw0rd'), diff --git a/spec/defines/db_spec.rb b/spec/defines/db_spec.rb index 8e743ff81..a846a775c 100644 --- a/spec/defines/db_spec.rb +++ b/spec/defines/db_spec.rb @@ -25,7 +25,7 @@ is_expected.to contain_mongodb_user('User testuser on db testdb'). \ with_username('testuser'). \ with_database('testdb'). \ - that_requires('Mongodb_database[testdb]') + that_comes_before('Mongodb_database[testdb]') end it 'contains mongodb_user with proper roles' do @@ -65,7 +65,7 @@ is_expected.to contain_mongodb_user('User testuser on db testdb'). \ with_username('testuser'). \ with_database('testdb'). \ - that_requires('Mongodb_database[testdb]') + that_comes_before('Mongodb_database[testdb]') end it 'contains mongodb_user with proper roles' do From 77fc5fc9d47152e151e3d56d680a4a5ca4482514 Mon Sep 17 00:00:00 2001 From: Steven POST Date: Thu, 28 Mar 2024 10:00:45 +0100 Subject: [PATCH 08/10] Fix authRequired function A curly brace was not placed properly. --- templates/mongoshrc.js.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/mongoshrc.js.erb b/templates/mongoshrc.js.erb index c15c52c30..c29c642f3 100644 --- a/templates/mongoshrc.js.erb +++ b/templates/mongoshrc.js.erb @@ -23,12 +23,12 @@ function authRequired() { } catch (err) { if (err.message.match(/requires authentication/) || err.message.match(/not authorized on admin/)) { return true + } if (err.message.match(/not running with --replSet/)) { return false } throw("Unknown error :" + err) } - } } if (authRequired()) { From b140a1876bde02a43315f10a11a200de43884a12 Mon Sep 17 00:00:00 2001 From: Steven POST Date: Thu, 28 Mar 2024 12:45:52 +0100 Subject: [PATCH 09/10] Fix weird message formatting --- templates/mongoshrc.js.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/mongoshrc.js.erb b/templates/mongoshrc.js.erb index c29c642f3..8cf62785c 100644 --- a/templates/mongoshrc.js.erb +++ b/templates/mongoshrc.js.erb @@ -27,7 +27,7 @@ function authRequired() { if (err.message.match(/not running with --replSet/)) { return false } - throw("Unknown error :" + err) + throw("Unknown error: " + err) } } From 263fc4f18f0ff4cbccc41e0910076d59cd640490 Mon Sep 17 00:00:00 2001 From: Steven POST Date: Thu, 28 Mar 2024 12:48:18 +0100 Subject: [PATCH 10/10] Avoid failing on auth for unconfigured replsets All errors not related to authentication mean that auth is not required. --- templates/mongoshrc.js.erb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/templates/mongoshrc.js.erb b/templates/mongoshrc.js.erb index 8cf62785c..c0e392f44 100644 --- a/templates/mongoshrc.js.erb +++ b/templates/mongoshrc.js.erb @@ -24,10 +24,7 @@ function authRequired() { if (err.message.match(/requires authentication/) || err.message.match(/not authorized on admin/)) { return true } - if (err.message.match(/not running with --replSet/)) { - return false - } - throw("Unknown error: " + err) + return false } }