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 40ce49e59..69f989c33 100644 --- a/lib/facter/is_master.rb +++ b/lib/facter/is_master.rb @@ -39,17 +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) - 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("mongosh --quiet #{options} --eval \"EJSON.stringify(db.adminCommand({ ping: 1 }))\"") if $CHILD_STATUS.success? - Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"#{e}db.isMaster().ismaster\"") + Facter::Core::Execution.exec("mongosh --quiet #{options} --eval \"db.isMaster().ismaster\"") else 'not_responding' end 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/lib/puppet/provider/mongodb.rb b/lib/puppet/provider/mongodb.rb index c5944ac6c..1c01cc5c1 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 @@ -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,11 +135,14 @@ 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' - 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 = mongosh_cmd(db, conn_string, cmd_ismaster).to_s.split(%r{\n}).last.chomp res.eql?('true') end @@ -156,14 +159,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 @@ -174,7 +177,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..1cf061d25 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'], @@ -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' diff --git a/lib/puppet/provider/mongodb_replset/mongo.rb b/lib/puppet/provider/mongodb_replset/mongo.rb index 7837533e2..3013da5e4 100644 --- a/lib/puppet/provider/mongodb_replset/mongo.rb +++ b/lib/puppet/provider/mongodb_replset/mongo.rb @@ -153,31 +153,36 @@ 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 = 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 + + # 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 +388,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/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/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..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'), @@ -28,8 +29,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 @@ -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'), @@ -54,9 +56,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 @@ -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'), @@ -82,8 +85,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 @@ -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'), @@ -111,8 +115,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 @@ -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'), @@ -148,25 +154,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/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 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 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 56% rename from templates/mongorc.js.erb rename to templates/mongoshrc.js.erb index 9e060306f..c0e392f44 100644 --- a/templates/mongorc.js.erb +++ b/templates/mongoshrc.js.erb @@ -19,31 +19,31 @@ function rsReconfigSettings(settings){ <% if @auth and @store_creds -%> function authRequired() { try { - return db.serverCmdLineOpts().code == 13; + return rs.status().ok != 1; } catch (err) { - return false; + if (err.message.match(/requires authentication/) || err.message.match(/not authorized on admin/)) { + return true + } + return false } } 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 -%>