Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/facter/is_master.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def 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 \"#{e}JSON.stringify(db.adminCommand({ ping: 1 }))\"")

if $CHILD_STATUS.success?
Facter::Core::Execution.exec("mongo --quiet #{options} --eval \"#{e}db.isMaster().ismaster\"")
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/provider/mongodb_database/mongodb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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())')
dbs = JSON.parse mongo_eval(pre_cmd + ';JSON.stringify(db.getMongo().getDBs())')

dbs['databases'].map do |db|
new(name: db['name'],
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/provider/mongodb_replset/mongo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def get_hosts_status(members)
raise Puppet::Error, "Can't configure replicaset #{name}, host #{host} is not supposed to be part of a replicaset."
end

if auth_enabled && status.key?('errmsg') && (status['errmsg'].include?('unauthorized') || status['errmsg'].include?('not authorized'))
if auth_enabled && status.key?('errmsg') && (status['errmsg'].include?('unauthorized') || status['errmsg'].include?('not authorized') || status['codeName'] == 'Unauthorized')
Puppet.warning "Host #{host} is available, but you are unauthorized because of authentication is enabled: #{auth_enabled}"
alive.push(member)
end
Expand Down Expand Up @@ -388,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("JSON.stringify(#{command})", 'admin', retries, host)
rescue Puppet::ExecutionFailure => e
Puppet.debug "Got an exception: #{e}"
raise
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/provider/mongodb_shard/mongo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def self.mongo_command(command, host = nil, _retries = 4)
args = []
args << '--quiet'
args << ['--host', host] if host
args << ['--eval', "printjson(#{command})"]
args << ['--eval', "JSON.stringify(#{command})"]
output = mongo(args.flatten)
rescue Puppet::ExecutionFailure => e
raise unless e =~ %r{Error: couldn't connect to server} && wait <= (2**max_wait)
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/provider/mongodb_user/mongodb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def self.instances
require 'json'

if db_ismaster
users = JSON.parse mongo_eval('printjson(db.system.users.find().toArray())')
users = JSON.parse mongo_eval('JSON.stringify(db.system.users.find().toArray())')

users.map do |user|
new(name: user['_id'],
Expand Down
25 changes: 25 additions & 0 deletions lib/puppet/util/mongodb_output.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
require 'json'

module Puppet
module Util
module MongodbOutput
def self.sanitize(data)
# If it already happily contains a valid json, do not do any sanitization
return data if is_parseable_json(data)

# Dirty hack to remove JavaScript objects
data.gsub!(%r{\w+\((\d+).+?\)}, '\1') # Remove extra parameters from 'Timestamp(1462971623, 1)' Objects
data.gsub!(%r{\w+\((.+?)\)}, '\1')

# Probably theres a json object that we could extract from the output
maybe_json = try_extract_json(data)
return maybe_json unless maybe_json.nil?

data.gsub!(%r{^Error\:.+}, '')
data.gsub!(%r{^.*warning\:.+}, '') # remove warnings if sslAllowInvalidHostnames is true
data.gsub!(%r{^.*The server certificate does not match the host name.+}, '') # remove warnings if sslAllowInvalidHostnames is true mongo 3.x
data
end

def self.is_parseable_json(data)
!!JSON.parse(data)
rescue JSON::ParserError
false
end

def self.try_extract_json(data)
json_data = data.dup
unescaped_quotes = json_data.scan(%r{:\s*"(.*"+.*)"}).flatten
for str in unescaped_quotes do
json_data.sub!(str, str.gsub('"', '\"'))
end
maybe_json = json_data.gsub(%r{^[^{]*(?<json>{[\P{Cn}\P{Cs}]*})[^}]*$}, '\k<json>')
maybe_json if is_parseable_json(maybe_json)
end
end
end
end
8 changes: 4 additions & 4 deletions spec/acceptance/database_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class { 'mongodb::server': }
apply_manifest(pp, catch_changes: true)
end
it 'creates the databases' do
shell("mongo testdb1 --eval 'printjson(db.getMongo().getDBs())'")
shell("mongo testdb2 --eval 'printjson(db.getMongo().getDBs())'")
shell("mongo testdb1 --eval 'JSON.stringify(db.getMongo().getDBs())'")
shell("mongo testdb2 --eval 'JSON.stringify(db.getMongo().getDBs())'")
end
end

Expand All @@ -46,8 +46,8 @@ class { 'mongodb::server':
apply_manifest(pp, catch_changes: true)
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("mongo testdb1 --port 27018 --eval 'JSON.stringify(db.getMongo().getDBs())'")
shell("mongo testdb2 --port 27018 --eval 'JSON.stringify(db.getMongo().getDBs())'")
end
end
end
Expand Down
12 changes: 6 additions & 6 deletions spec/acceptance/replset_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,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'), 'mongo --quiet --eval "JSON.stringify(rs.conf())"') do |r|
expect(r.stdout).to match %r{#{hosts[0]}:27017}
expect(r.stdout).to match %r{#{hosts[1]}:27017}
end
Expand All @@ -58,14 +58,14 @@ class { 'mongodb::client': }
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'), %{mongo --verbose --eval 'JSON.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'), %{mongo --verbose --eval 'try { rs.secondaryOk() } catch (err) { rs.slaveOk() }; JSON.stringify(db.test.findOne({name:"test1"}))'} do |r|
expect(r.stdout).to match %r{some value}
end
end
Expand Down Expand Up @@ -174,7 +174,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'), 'mongo --quiet --eval "load(\'/root/.mongorc.js\');JSON.stringify(rs.conf())"') do |r|
expect(r.stdout).to match %r{#{hosts[0]}:27017}
expect(r.stdout).to match %r{#{hosts[1]}:27017}
end
Expand All @@ -187,14 +187,14 @@ class { 'mongodb::server':
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'), %{mongo test --verbose --eval 'load("/root/.mongorc.js");JSON.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'), %{mongo test --verbose --eval 'load("/root/.mongorc.js");try { rs.secondaryOk() } catch (err) { rs.slaveOk() };JSON.stringify(db.dummyData.findOne())'} do |r|
expect(r.stdout).to match %r{created_by_puppet}
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/acceptance/server_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class { 'mongodb::client': }
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("mongo admin --quiet --eval \"load('/root/.mongorc.js');JSON.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" }
end
Expand Down
2 changes: 1 addition & 1 deletion spec/acceptance/sharding_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,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'), 'mongo --quiet --eval "JSON.stringify(sh.status())"') do |r|
expect(r.stdout).to match %r{foo\/shard:27018}
expect(r.stdout).to match %r{foo\.toto}
end
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/puppet/provider/mongodb_database/mongodb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,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('try { rs.secondaryOk() } catch (err) { rs.slaveOk() };JSON.stringify(db.getMongo().getDBs())').and_return(raw_dbs)
allow(provider.class).to receive(:db_ismaster).and_return(true)
end

Expand Down
2 changes: 1 addition & 1 deletion spec/unit/puppet/provider/mongodb_user/mongodb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,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('JSON.stringify(db.system.users.find().toArray())').and_return(raw_users)
allow(provider.class).to receive(:mongo_version).and_return('2.6.x')
allow(provider.class).to receive(:db_ismaster).and_return(true)
end
Expand Down
48 changes: 48 additions & 0 deletions spec/unit/puppet/util/mongodb_output_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,45 @@
EOT
end

let(:corrupted_output) do
<<-EOT
Error: Authentication failed.
2021-05-11T15:35:19.647+0200 E QUERY [thread1] Error: Could not retrieve replica set config: {
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { replSetGetConfig: 1.0, $clusterTime: { clusterTime: Timestamp(0, 0), signature: { hash: BinData(0, 0000000000000000000000000000000000000000), keyId: 0 } }, $readPreference: { mode: \"secondaryPreferred\" }, $db: \"admin\" }",
"code" : 13,
"codeName" : "Unauthorized",
"$clusterTime" : {
"clusterTime" : Timestamp(0, 0),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
rs.conf@src/mongo/shell/utils.js:1323:11
@(shell eval):1:43'
EOT
end

let(:corrected_corrupted_output) do
<<-EOT
{
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { replSetGetConfig: 1.0, $clusterTime: { clusterTime: 0, signature: { hash: 0, keyId: 0 } }, $readPreference: { mode: \\"secondaryPreferred\\" }, $db: \\"admin\\" }",
"code" : 13,
"codeName" : "Unauthorized",
"$clusterTime" : {
"clusterTime" : 0,
"signature" : {
"hash" : 0,
"keyId" : 0
}
}
}
EOT
end

describe '.sanitize' do
it 'returns a valid json' do
sanitized_json = described_class.sanitize(bson_data)
Expand All @@ -62,5 +101,14 @@
sanitized_json = described_class.sanitize(bson_data)
expect(JSON.parse(sanitized_json)).to include(JSON.parse(json_data))
end

it 'extracts json from a corrupted output' do
sanitized_json = described_class.sanitize(corrupted_output)
expect(JSON.parse(sanitized_json)).to eq(JSON.parse(corrected_corrupted_output))
end

it 'returns string as is if no json there' do
expect(described_class.sanitize('3.6.3')).to eq('3.6.3')
end
end
end