4545 - The port to connect to
4646 required: false
4747 default: 27017
48+ login_database:
49+ description:
50+ - The database where login credentials are stored
51+ required: false
52+ default: admin
4853 replica_set:
4954 description:
5055 - Replica set to connect to (automatically connects to primary for writes)
6974 description:
7075 - Whether to use an SSL connection when connecting to the database
7176 default: False
77+ ssl_cert_reqs:
78+ description:
79+ - Specifies whether a certificate is required from the other side of the connection, and whether it will be validated if provided.
80+ required: false
81+ default: "CERT_REQUIRED"
82+ choices: ["CERT_REQUIRED", "CERT_OPTIONAL", "CERT_NONE"]
7283 build_indexes:
7384 description:
7485 - Determines whether the mongod builds indexes on this member.
146157 sample: "replica"
147158'''
148159import ConfigParser
160+ import ssl as ssl_lib
149161import time
162+ from datetime import datetime as dtdatetime
150163from distutils .version import LooseVersion
151164try :
152165 from pymongo .errors import ConnectionFailure
156169 from pymongo .errors import ServerSelectionTimeoutError
157170 from pymongo import version as PyMongoVersion
158171 from pymongo import MongoClient
159- from pymongo import MongoReplicaSetClient
160172except ImportError :
161173 pymongo_found = False
162174else :
@@ -203,6 +215,7 @@ def check_members(state, module, client, host_name, host_port, host_type):
203215 module .exit_json (changed = False , host_name = host_name , host_port = host_port , host_type = host_type )
204216
205217def add_host (module , client , host_name , host_port , host_type , timeout = 180 , ** kwargs ):
218+ start_time = dtdatetime .now ()
206219 while True :
207220 try :
208221 admin_db = client ['admin' ]
@@ -240,12 +253,12 @@ def add_host(module, client, host_name, host_port, host_type, timeout=180, **kwa
240253 admin_db .command ('replSetReconfig' , cfg )
241254 return
242255 except (OperationFailure , AutoReconnect ) as e :
243- timeout = timeout - 5
244- if timeout <= 0 :
256+ if (dtdatetime .now () - start_time ).seconds > timeout :
245257 module .fail_json (msg = 'reached timeout while waiting for rs.reconfig(): %s' % str (e ))
246258 time .sleep (5 )
247259
248260def remove_host (module , client , host_name , timeout = 180 ):
261+ start_time = dtdatetime .now ()
249262 while True :
250263 try :
251264 admin_db = client ['admin' ]
@@ -269,8 +282,7 @@ def remove_host(module, client, host_name, timeout=180):
269282 fail_msg = "couldn't find member with hostname: {0} in replica set members list" .format (host_name )
270283 module .fail_json (msg = fail_msg )
271284 except (OperationFailure , AutoReconnect ) as e :
272- timeout = timeout - 5
273- if timeout <= 0 :
285+ if (dtdatetime .now () - start_time ).seconds > timeout :
274286 module .fail_json (msg = 'reached timeout while waiting for rs.reconfig(): %s' % str (e ))
275287 time .sleep (5 )
276288
@@ -289,14 +301,23 @@ def load_mongocnf():
289301
290302 return creds
291303
292- def wait_for_ok_and_master (module , client , timeout = 60 ):
304+ def wait_for_ok_and_master (module , connection_params , timeout = 180 ):
305+ start_time = dtdatetime .now ()
293306 while True :
294- status = client .admin .command ('replSetGetStatus' , check = False )
295- if status ['ok' ] == 1 and status ['myState' ] == 1 :
296- return
307+ try :
308+ client = MongoClient (** connection_params )
309+ authenticate (client , connection_params ["username" ], connection_params ["password" ])
310+
311+ status = client .admin .command ('replSetGetStatus' , check = False )
312+ if status ['ok' ] == 1 and status ['myState' ] == 1 :
313+ return
314+
315+ except ServerSelectionTimeoutError :
316+ pass
297317
298- timeout = timeout - 1
299- if timeout == 0 :
318+ client .close ()
319+
320+ if (dtdatetime .now () - start_time ).seconds > timeout :
300321 module .fail_json (msg = 'reached timeout while waiting for rs.status() to become ok=1' )
301322
302323 time .sleep (1 )
@@ -324,11 +345,13 @@ def main():
324345 login_password = dict (default = None , no_log = True ),
325346 login_host = dict (default = 'localhost' ),
326347 login_port = dict (default = '27017' ),
348+ login_database = dict (default = "admin" ),
327349 replica_set = dict (default = None ),
328350 host_name = dict (default = 'localhost' ),
329351 host_port = dict (default = '27017' ),
330352 host_type = dict (default = 'replica' , choices = ['replica' ,'arbiter' ]),
331- ssl = dict (default = 'false' ),
353+ ssl = dict (default = False , type = 'bool' ),
354+ ssl_cert_reqs = dict (default = 'CERT_REQUIRED' , choices = ['CERT_NONE' , 'CERT_OPTIONAL' , 'CERT_REQUIRED' ]),
332355 build_indexes = dict (type = 'bool' , default = 'yes' ),
333356 hidden = dict (type = 'bool' , default = 'no' ),
334357 priority = dict (default = '1.0' ),
@@ -339,12 +362,13 @@ def main():
339362 )
340363
341364 if not pymongo_found :
342- module .fail_json (msg = 'the python pymongo (>= 2.4 ) module is required' )
365+ module .fail_json (msg = 'the python pymongo (>= 3.2 ) module is required' )
343366
344367 login_user = module .params ['login_user' ]
345368 login_password = module .params ['login_password' ]
346369 login_host = module .params ['login_host' ]
347370 login_port = module .params ['login_port' ]
371+ login_database = module .params ['login_database' ]
348372 replica_set = module .params ['replica_set' ]
349373 host_name = module .params ['host_name' ]
350374 host_port = module .params ['host_port' ]
@@ -359,29 +383,58 @@ def main():
359383 if replica_set is None :
360384 module .fail_json (msg = 'replica_set parameter is required' )
361385 else :
362- client = MongoClient (login_host , int (login_port ), replicaSet = replica_set ,
363- ssl = ssl , serverSelectionTimeoutMS = 5000 )
364-
386+ connection_params = {
387+ "host" : login_host ,
388+ "port" : int (login_port ),
389+ "username" : login_user ,
390+ "password" : login_password ,
391+ "authsource" : login_database ,
392+ "serverselectiontimeoutms" : 5000 ,
393+ "replicaset" : replica_set ,
394+ }
395+
396+ if ssl :
397+ connection_params ["ssl" ] = ssl
398+ connection_params ["ssl_cert_reqs" ] = getattr (ssl_lib , module .params ['ssl_cert_reqs' ])
399+
400+ client = MongoClient (** connection_params )
365401 authenticate (client , login_user , login_password )
366402 client ['admin' ].command ('replSetGetStatus' )
367403
368404 except ServerSelectionTimeoutError :
369405 try :
370- client = MongoClient (login_host , int (login_port ), ssl = ssl )
406+ connection_params = {
407+ "host" : login_host ,
408+ "port" : int (login_port ),
409+ "username" : login_user ,
410+ "password" : login_password ,
411+ "authsource" : login_database ,
412+ "serverselectiontimeoutms" : 10000 ,
413+ }
414+
415+ if ssl :
416+ connection_params ["ssl" ] = ssl
417+ connection_params ["ssl_cert_reqs" ] = getattr (ssl_lib , module .params ['ssl_cert_reqs' ])
418+
419+ client = MongoClient (** connection_params )
371420 authenticate (client , login_user , login_password )
372421 if state == 'present' :
373422 new_host = { '_id' : 0 , 'host' : "{0}:{1}" .format (host_name , host_port ) }
374423 if priority != 1.0 : new_host ['priority' ] = priority
375424 config = { '_id' : "{0}" .format (replica_set ), 'members' : [new_host ] }
376425 client ['admin' ].command ('replSetInitiate' , config )
377- wait_for_ok_and_master (module , client )
426+ client .close ()
427+ wait_for_ok_and_master (module , connection_params )
378428 replica_set_created = True
379429 module .exit_json (changed = True , host_name = host_name , host_port = host_port , host_type = host_type )
380430 except OperationFailure as e :
381431 module .fail_json (msg = 'Unable to initiate replica set: %s' % str (e ))
382432 except ConnectionFailure as e :
383433 module .fail_json (msg = 'unable to connect to database: %s' % str (e ))
384434
435+ # reconnect again
436+ client = MongoClient (** connection_params )
437+ authenticate (client , login_user , login_password )
385438 check_compatibility (module , client )
386439 check_members (state , module , client , host_name , host_port , host_type )
387440
0 commit comments