Skip to content

Commit e230c29

Browse files
Johan De Witstevenpost
Johan De Wit
authored andcommitted
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.
1 parent 30a6905 commit e230c29

File tree

23 files changed

+125
-120
lines changed

23 files changed

+125
-120
lines changed

REFERENCE.md

+9
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ The following parameters are available in the `mongodb::globals` class:
127127

128128
* [`server_package_name`](#-mongodb--globals--server_package_name)
129129
* [`client_package_name`](#-mongodb--globals--client_package_name)
130+
* [`client_version`](#-mongodb--globals--client_version)
130131
* [`mongod_service_manage`](#-mongodb--globals--mongod_service_manage)
131132
* [`service_enable`](#-mongodb--globals--service_enable)
132133
* [`service_ensure`](#-mongodb--globals--service_ensure)
@@ -168,6 +169,14 @@ If not specified, the module will use whatever service name is the default for y
168169

169170
Default value: `undef`
170171

172+
##### <a name="-mongodb--globals--client_version"></a>`client_version`
173+
174+
Data type: `Any`
175+
176+
Version of the client package to install.
177+
178+
Default value: `undef`
179+
171180
##### <a name="-mongodb--globals--mongod_service_manage"></a>`mongod_service_manage`
172181

173182
Data type: `Any`

lib/facter/is_master.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ def get_options_from_config(file)
3939

4040
Facter.add('mongodb_is_master') do
4141
setcode do
42-
if %w[mongo mongod].all? { |m| Facter::Util::Resolution.which m }
42+
if %w[mongosh mongod].all? { |m| Facter::Util::Resolution.which m }
4343
file = mongod_conf_file
4444
if file
4545
options = get_options_from_config(file)
46-
e = File.exist?('/root/.mongorc.js') ? 'load(\'/root/.mongorc.js\'); ' : ''
46+
e = File.exist?('/root/.mongoshrc.js') ? 'load(\'/root/.mongoshrc.js\'); ' : ''
4747

4848
# Check if the mongodb server is responding:
49-
Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"#{e}printjson(db.adminCommand({ ping: 1 }))\"")
49+
Facter::Core::Execution.exec("mongosh --quiet #{options} --eval \"#{e}EJSON.stringify(db.adminCommand({ ping: 1 }))\"")
5050

5151
if $CHILD_STATUS.success?
52-
Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"#{e}db.isMaster().ismaster\"")
52+
Facter::Core::Execution.exec("mongosh --quiet #{options} --eval \"#{e}db.isMaster().ismaster\"")
5353
else
5454
'not_responding'
5555
end

lib/puppet/provider/mongodb.rb

+12-12
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
class Puppet::Provider::Mongodb < Puppet::Provider
99
# Without initvars commands won't work.
1010
initvars
11-
commands mongo: 'mongo'
11+
commands mongosh: 'mongosh'
1212

1313
# Optional defaults file
14-
def self.mongorc_file
15-
"load('#{Facter.value(:root_home)}/.mongorc.js'); " if File.file?("#{Facter.value(:root_home)}/.mongorc.js")
14+
def self.mongoshrc_file
15+
"load('#{Facter.value(:root_home)}/.mongoshrc.js'); " if File.file?("#{Facter.value(:root_home)}/.mongoshrc.js")
1616
end
1717

18-
def mongorc_file
19-
self.class.mongorc_file
18+
def mongoshrc_file
19+
self.class.mongoshrc_file
2020
end
2121

2222
def self.mongod_conf_file
@@ -74,7 +74,7 @@ def self.tls_invalid_hostnames(config = nil)
7474
config['tlsallowInvalidHostnames']
7575
end
7676

77-
def self.mongo_cmd(db, host, cmd)
77+
def self.mongosh_cmd(db, host, cmd)
7878
config = mongo_conf
7979

8080
args = [db, '--quiet', '--host', host]
@@ -101,7 +101,7 @@ def self.mongo_cmd(db, host, cmd)
101101
end
102102

103103
args += ['--eval', cmd]
104-
mongo(args)
104+
mongosh(args)
105105
end
106106

107107
def self.conn_string
@@ -138,7 +138,7 @@ def self.conn_string
138138
def self.db_ismaster
139139
cmd_ismaster = 'db.isMaster().ismaster'
140140
db = 'admin'
141-
res = mongo_cmd(db, conn_string, cmd_ismaster).to_s.split(%r{\n}).last.chomp
141+
res = mongosh_cmd(db, conn_string, cmd_ismaster).to_s.split(%r{\n}).last.chomp
142142
res.eql?('true')
143143
end
144144

@@ -155,14 +155,14 @@ def self.auth_enabled(config = nil)
155155
def self.mongo_eval(cmd, db = 'admin', retries = 10, host = nil)
156156
retry_count = retries
157157
retry_sleep = 3
158-
cmd = mongorc_file + cmd if mongorc_file
158+
cmd = mongoshrc_file + cmd if mongoshrc_file
159159

160160
out = nil
161161
begin
162162
out = if host
163-
mongo_cmd(db, host, cmd)
163+
mongosh_cmd(db, host, cmd)
164164
else
165-
mongo_cmd(db, conn_string, cmd)
165+
mongosh_cmd(db, conn_string, cmd)
166166
end
167167
rescue StandardError => e
168168
retry_count -= 1
@@ -173,7 +173,7 @@ def self.mongo_eval(cmd, db = 'admin', retries = 10, host = nil)
173173
end
174174
end
175175

176-
raise Puppet::ExecutionFailure, "Could not evaluate MongoDB shell command: #{cmd}" unless out
176+
raise Puppet::ExecutionFailure, "Could not evaluate MongoDB shell command: #{cmd}, with: #{e.message}" unless out
177177

178178
Puppet::Util::MongodbOutput.sanitize(out)
179179
end

lib/puppet/provider/mongodb_database/mongodb.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
def self.instances
1010
require 'json'
1111

12-
pre_cmd = 'try { rs.secondaryOk() } catch (err) { rs.slaveOk() }'
13-
dbs = JSON.parse mongo_eval("#{pre_cmd};printjson(db.getMongo().getDBs())")
12+
pre_cmd = 'db.getMongo().setReadPref("primaryPreferred")'
13+
dbs = JSON.parse mongo_eval("#{pre_cmd};EJSON.stringify(db.getMongo().getDBs())")
1414

1515
dbs['databases'].map do |db|
1616
new(name: db['name'],

lib/puppet/provider/mongodb_replset/mongo.rb

+26-25
Original file line numberDiff line numberDiff line change
@@ -153,31 +153,32 @@ def get_hosts_status(members)
153153
members.select do |member|
154154
host = member['host']
155155
Puppet.debug "Checking replicaset member #{host} ..."
156-
status = rs_status(host)
157-
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'
158-
159-
if auth_enabled && status.key?('errmsg') && (status['errmsg'].include?('unauthorized') || status['errmsg'].include?('not authorized') || status['errmsg'].include?('requires authentication'))
160-
Puppet.warning "Host #{host} is available, but you are unauthorized because of authentication is enabled: #{auth_enabled}"
161-
alive.push(member)
162-
end
163-
164-
if status.key?('errmsg') && status['errmsg'].include?('no replset config has been received')
165-
Puppet.debug 'Mongo v4 rs.status() RS not initialized output'
166-
alive.push(member)
167-
end
168-
169-
if status.key?('set')
170-
raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is already part of another replicaset." if status['set'] != name
171-
172-
# This node is alive and supposed to be a member of our set
173-
Puppet.debug "Host #{host} is available for replset #{status['set']}"
174-
alive.push(member)
175-
elsif status.key?('info')
176-
Puppet.debug "Host #{host} is alive but unconfigured: #{status['info']}"
177-
alive.push(member)
156+
begin
157+
status = rs_status(host)
158+
159+
if status.key?('set')
160+
raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is already part of another replicaset." if status['set'] != name
161+
162+
# This node is alive and supposed to be a member of our set
163+
Puppet.debug "Host #{host} is available for replset #{status['set']}"
164+
alive.push(member)
165+
elsif status.key?('info')
166+
Puppet.debug "Host #{host} is alive but unconfigured: #{status['info']}"
167+
alive.push(member)
168+
end
169+
rescue Puppet::ExecutionFailure => e
170+
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}
171+
172+
if auth_enabled && (e.message.include?('unauthorized') || e.message.include?('not authorized') || e.message.include?('requires authentication'))
173+
Puppet.warning "Host #{host} is available, but you are unauthorized because of authentication is enabled: #{auth_enabled}"
174+
alive.push(member)
175+
elsif e.message.include?('no replset config has been received')
176+
Puppet.debug 'Mongo v4 rs.status() RS not initialized output'
177+
alive.push(member)
178+
else
179+
Puppet.warning "Can't connect to replicaset member #{host}."
180+
end
178181
end
179-
rescue Puppet::ExecutionFailure
180-
Puppet.warning "Can't connect to replicaset member #{host}."
181182
end
182183
alive.uniq!
183184
dead = members - alive
@@ -383,7 +384,7 @@ def mongo_command(command, host, retries = 4)
383384

384385
def self.mongo_command(command, host = nil, retries = 4)
385386
begin
386-
output = mongo_eval("printjson(#{command})", 'admin', retries, host)
387+
output = mongo_eval("EJSON.stringify(#{command})", 'admin', retries, host)
387388
rescue Puppet::ExecutionFailure => e
388389
Puppet.debug "Got an exception: #{e}"
389390
raise

lib/puppet/provider/mongodb_shard/mongo.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
mk_resource_methods
1515

16-
commands mongo: 'mongo'
16+
commands mongosh: 'mongosh'
1717

1818
def initialize(value = {})
1919
super(value)
@@ -152,8 +152,8 @@ def self.mongo_command(command, host = nil, _retries = 4)
152152
args = []
153153
args << '--quiet'
154154
args << ['--host', host] if host
155-
args << ['--eval', "printjson(#{command})"]
156-
output = mongo(args.flatten)
155+
args << ['--eval', "EJSON.stringify(#{command})"]
156+
output = mongosh(args.flatten)
157157
rescue Puppet::ExecutionFailure => e
158158
raise unless e =~ %r{Error: couldn't connect to server} && wait <= (2**max_wait)
159159

lib/puppet/provider/mongodb_user/mongodb.rb

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ def self.instances
1010
require 'json'
1111

1212
if db_ismaster
13-
script = 'printjson(db.system.users.find().toArray())'
13+
script = 'EJSON.stringify(db.system.users.find().toArray())'
1414
# A hack to prevent prefetching failures until admin user is created
15-
script = "try {#{script}} catch (e) { if (e.message.match(/not authorized on admin/)) { 'not authorized on admin' } else {throw e}}" if auth_enabled
15+
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
1616

1717
out = mongo_eval(script)
18-
19-
return [] if auth_enabled && out.include?('not authorized on admin')
18+
return [] if auth_enabled && (out.include?('requires authentication') || out.include?('not authorized on admin'))
2019

2120
users = JSON.parse out
2221

manifests/client/params.pp

+4-10
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,10 @@
33
# @api private
44
#
55
class mongodb::client::params inherits mongodb::globals {
6-
$package_ensure = pick($mongodb::globals::version, 'present')
6+
$package_ensure = pick($mongodb::globals::client_version, 'present')
77
$manage_package = pick($mongodb::globals::manage_package, $mongodb::globals::manage_package_repo, false)
88

9-
if $manage_package {
10-
$package_name = "mongodb-${mongodb::globals::edition}-shell"
11-
} else {
12-
$package_name = $facts['os']['family'] ? {
13-
'Debian' => 'mongodb-clients',
14-
'Redhat' => "mongodb-${mongodb::globals::edition}-shell",
15-
default => 'mongodb',
16-
}
17-
}
9+
# the new mongosh package is the same for all distros.
10+
# and it follows its own versioning
11+
$package_name = 'mongodb-mongosh'
1812
}

manifests/globals.pp

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
# This setting can be used to specify the name of the client package that should be installed.
3737
# If not specified, the module will use whatever service name is the default for your OS distro.
3838
#
39+
# @param client_version
40+
# Version of the client package to install.
3941
# @param mongod_service_manage
4042
# This setting can be used to override the default management of the mongod service.
4143
# By default the module will manage the mongod process.
@@ -118,6 +120,7 @@
118120
class mongodb::globals (
119121
$server_package_name = undef,
120122
$client_package_name = undef,
123+
$client_version = undef,
121124

122125
$mongod_service_manage = undef,
123126
$service_enable = undef,

manifests/params.pp

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
]
2323
$handle_creds = true
2424
$store_creds = false
25-
$rcfile = "${facts['root_home']}/.mongorc.js"
25+
$rcfile = "${facts['root_home']}/.mongoshrc.js"
2626
$dbpath_fix = false
2727

2828
$manage_package = pick($mongodb::globals::manage_package, $mongodb::globals::manage_package_repo, false)

manifests/server/config.pp

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@
179179
if $handle_creds {
180180
file { $rcfile:
181181
ensure => file,
182-
content => template('mongodb/mongorc.js.erb'),
182+
content => template('mongodb/mongoshrc.js.erb'),
183183
owner => 'root',
184184
group => 'root',
185185
mode => '0600',

spec/acceptance/database_spec.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class { 'mongodb::server': }
2323
end
2424

2525
it 'creates the databases' do
26-
shell("mongo testdb1 --eval 'printjson(db.getMongo().getDBs())'")
27-
shell("mongo testdb2 --eval 'printjson(db.getMongo().getDBs())'")
26+
shell("mongosh testdb1 --eval 'EJSON.stringify(db.getMongo().getDBs())'")
27+
shell("mongosh testdb2 --eval 'EJSON.stringify(db.getMongo().getDBs())'")
2828
end
2929
end
3030

@@ -50,8 +50,8 @@ class { 'mongodb::server':
5050
end
5151

5252
it 'creates the database' do
53-
shell("mongo testdb1 --port 27018 --eval 'printjson(db.getMongo().getDBs())'")
54-
shell("mongo testdb2 --port 27018 --eval 'printjson(db.getMongo().getDBs())'")
53+
shell("mongosh testdb1 --port 27018 --eval 'EJSON.stringify(db.getMongo().getDBs())'")
54+
shell("mongosh testdb2 --port 27018 --eval 'EJSON.stringify(db.getMongo().getDBs())'")
5555
end
5656
end
5757
end

spec/acceptance/mongos_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class { 'mongodb::server':
4646
it { is_expected.to be_listening }
4747
end
4848

49-
describe command('mongo --version') do
49+
describe command('mongod --version') do
5050
its(:exit_status) { is_expected.to eq 0 }
5151
end
5252
end

0 commit comments

Comments
 (0)