1
|
|
|
require 'yaml' |
2
|
|
|
require 'json' |
3
|
|
|
class Puppet::Provider::Mongodb < Puppet::Provider |
4
|
|
|
|
5
|
|
|
# Without initvars commands won't work. |
6
|
|
|
initvars |
7
|
|
|
commands :mongo => 'mongo' |
8
|
|
|
|
9
|
|
|
# Optional defaults file |
10
|
|
|
def self.mongorc_file |
11
|
|
|
if File.file?("#{Facter.value(:root_home)}/.mongorc.js") |
12
|
|
|
"load('#{Facter.value(:root_home)}/.mongorc.js'); " |
13
|
|
|
else |
14
|
|
|
nil |
15
|
|
|
end |
16
|
|
|
end |
17
|
|
|
|
18
|
|
|
def mongorc_file |
19
|
|
|
self.class.mongorc_file |
20
|
|
|
end |
21
|
|
|
|
22
|
|
|
def self.get_mongod_conf_file |
23
|
|
|
if File.exists? '/etc/mongod.conf' |
24
|
|
|
file = '/etc/mongod.conf' |
25
|
|
|
else |
26
|
|
|
file = '/etc/mongodb.conf' |
27
|
|
|
end |
28
|
|
|
file |
29
|
|
|
end |
30
|
|
|
|
31
|
|
|
def self.get_conn_string |
32
|
|
|
file = get_mongod_conf_file |
33
|
|
|
# The mongo conf is probably a key-value store, even though 2.6 is |
34
|
|
|
# supposed to use YAML, because the config template is applied |
35
|
|
|
# based on $::mongodb::globals::version which is the user will not |
36
|
|
|
# necessarily set. This attempts to get the port from both types of |
37
|
|
|
# config files. |
38
|
|
|
config = YAML.load_file(file) |
39
|
|
|
if config.kind_of?(Hash) # Using a valid YAML file for mongo 2.6 |
40
|
|
|
bindip = config['net.bindIp'] |
41
|
|
|
port = config['net.port'] |
42
|
|
|
shardsvr = config['sharding.clusterRole'] |
43
|
|
|
confsvr = config['sharding.clusterRole'] |
44
|
|
|
else # It has to be a key-value config file |
45
|
|
|
config = {} |
46
|
|
|
File.readlines(file).collect do |line| |
47
|
|
|
k,v = line.split('=') |
48
|
|
|
config[k.rstrip] = v.lstrip.chomp if k and v |
49
|
|
|
end |
50
|
|
|
bindip = config['bind_ip'] |
51
|
|
|
port = config['port'] |
52
|
|
|
shardsvr = config['shardsvr'] |
53
|
|
|
confsvr = config['confsvr'] |
54
|
|
|
end |
55
|
|
|
|
56
|
|
|
if bindip |
57
|
|
|
first_ip_in_list = bindip.split(',').first |
58
|
|
|
if first_ip_in_list.eql? '0.0.0.0' |
59
|
|
|
ip_real = '127.0.0.1' |
60
|
|
|
else |
61
|
|
|
ip_real = first_ip_in_list |
62
|
|
|
end |
63
|
|
|
end |
64
|
|
|
|
65
|
|
|
if port |
66
|
|
|
port_real = port |
67
|
|
|
elsif !port and (confsvr.eql? 'configsvr' or confsvr.eql? 'true') |
68
|
|
|
port_real = 27019 |
69
|
|
|
elsif !port and (shardsvr.eql? 'shardsvr' or shardsvr.eql? 'true') |
70
|
|
|
port_real = 27018 |
71
|
|
|
else |
72
|
|
|
port_real = 27017 |
73
|
|
|
end |
74
|
|
|
|
75
|
|
|
"#{ip_real}:#{port_real}" |
76
|
|
|
end |
77
|
|
|
|
78
|
|
|
def self.db_ismaster |
79
|
|
|
cmd_ismaster = 'printjson(db.isMaster())' |
80
|
|
|
if mongorc_file |
81
|
|
|
cmd_ismaster = mongorc_file + cmd_ismaster |
82
|
|
|
end |
83
|
|
|
out = mongo(['admin', '--quiet', '--host', get_conn_string, '--eval', cmd_ismaster]) |
84
|
|
|
out.gsub!(/ObjectId\(([^)]*)\)/, '\1') |
85
|
|
|
out.gsub!(/ISODate\((.+?)\)/, '\1 ') |
86
|
|
|
out.gsub!(/^Error\:.+/, '') |
87
|
|
|
res = JSON.parse out |
88
|
|
|
|
89
|
|
|
return res['ismaster'] |
90
|
|
|
end |
91
|
|
|
|
92
|
|
|
def db_ismaster |
93
|
|
|
self.class.db_ismaster |
94
|
|
|
end |
95
|
|
|
|
96
|
|
|
def self.auth_enabled |
97
|
|
|
auth_enabled = false |
98
|
|
|
file = get_mongod_conf_file |
99
|
|
|
config = YAML.load_file(file) |
100
|
|
|
if config.kind_of?(Hash) |
101
|
|
|
auth_enabled = config['security.authorization'] |
102
|
|
|
else # It has to be a key-value store |
103
|
|
|
config = {} |
104
|
|
|
File.readlines(file).collect do |line| |
105
|
|
|
k,v = line.split('=') |
106
|
|
|
config[k.rstrip] = v.lstrip.chomp if k and v |
107
|
|
|
end |
108
|
|
|
auth_enabled = config['auth'] |
109
|
|
|
end |
110
|
|
|
return auth_enabled |
111
|
|
|
end |
112
|
|
|
|
113
|
|
|
# Mongo Command Wrapper |
114
|
|
|
def self.mongo_eval(cmd, db = 'admin', retries = 10, host = nil) |
115
|
|
|
retry_count = retries |
116
|
|
|
retry_sleep = 3 |
117
|
|
|
if mongorc_file |
118
|
|
|
cmd = mongorc_file + cmd |
119
|
|
|
end |
120
|
|
|
|
121
|
|
|
out = nil |
122
|
|
|
retry_count.times do |n| |
123
|
|
|
begin |
124
|
|
|
if host |
125
|
|
|
out = mongo([db, '--quiet', '--host', host, '--eval', cmd]) |
126
|
|
|
else |
127
|
|
|
out = mongo([db, '--quiet', '--host', get_conn_string, '--eval', cmd]) |
128
|
|
|
end |
129
|
|
|
rescue => e |
130
|
|
|
Puppet.debug "Request failed: '#{e.message}' Retry: '#{n}'" |
131
|
|
|
sleep retry_sleep |
132
|
|
|
next |
133
|
|
|
end |
134
|
|
|
break |
135
|
|
|
end |
136
|
|
|
|
137
|
|
|
if !out |
138
|
|
|
raise Puppet::ExecutionFailure, "Could not evalute MongoDB shell command: #{cmd}" |
139
|
|
|
end |
140
|
|
|
|
141
|
|
|
out.gsub!(/ObjectId\(([^)]*)\)/, '\1') |
142
|
|
|
out.gsub!(/^Error\:.+/, '') |
143
|
|
|
out |
144
|
|
|
end |
145
|
|
|
|
146
|
|
|
def mongo_eval(cmd, db = 'admin', retries = 10, host = nil) |
147
|
|
|
self.class.mongo_eval(cmd, db, retries, host) |
148
|
|
|
end |
149
|
|
|
|
150
|
|
|
# Mongo Version checker |
151
|
|
|
def self.mongo_version |
152
|
|
|
@@mongo_version ||= self.mongo_eval('db.version()') |
|
|
|
|
153
|
|
|
end |
154
|
|
|
|
155
|
|
|
def mongo_version |
156
|
|
|
self.class.mongo_version |
157
|
|
|
end |
158
|
|
|
|
159
|
|
|
def self.mongo_24? |
160
|
|
|
v = self.mongo_version |
161
|
|
|
! v[/^2\.4\./].nil? |
162
|
|
|
end |
163
|
|
|
|
164
|
|
|
def mongo_24? |
165
|
|
|
self.class.mongo_24? |
166
|
|
|
end |
167
|
|
|
|
168
|
|
|
end |
169
|
|
|
|