125125EXAMPLES = '''
126126# Add 'mongo1.dev:27017' host into replica set as replica (Replica will be initiated if it not exists)
127127- mongodb_replication: replica_set=replSet host_name=mongo1.dev host_port=27017 state=present
128-
129128# Add 'mongo2.dev:30000' host into replica set as arbiter
130129- mongodb_replication: replica_set=replSet host_name=mongo2.dev host_port=30000 host_type=arbiter state=present
131-
132130# Add 'mongo3.dev:27017' host into replica set as replica and authorization params
133131- mongodb_replication: replica_set=replSet login_host=mongo1.dev login_user=siteRootAdmin login_password=123456 host_name=mongo3.dev host_port=27017 state=present
134-
135132# Add 'mongo4.dev:27017' host into replica set as replica via SSL
136133- mongodb_replication: replica_set=replSet host_name=mongo4.dev host_port=27017 ssl=True state=present
137-
138134# Remove 'mongo4.dev:27017' host from the replica set
139135- mongodb_replication: replica_set=replSet host_name=mongo4.dev host_port=27017 state=absent
140136'''
@@ -204,6 +200,7 @@ def check_members(state, module, client, host_name, host_port, host_type):
204200 if not cfg :
205201 module .fail_json (msg = 'no config object retrievable from local.system.replset' )
206202
203+ found_on_remove = False
207204 for member in cfg ['members' ]:
208205 if state == 'present' :
209206 if host_type == 'replica' :
@@ -212,13 +209,17 @@ def check_members(state, module, client, host_name, host_port, host_type):
212209 else :
213210 if "{0}:{1}" .format (host_name , host_port ) in member ['host' ] and member ['arbiterOnly' ]:
214211 module .exit_json (changed = False , host_name = host_name , host_port = host_port , host_type = host_type )
215- else :
212+
213+ if state == 'absent' :
216214 if host_type == 'replica' :
217- if "{0}:{1}" .format (host_name , host_port ) not in member ['host' ]:
218- module . exit_json ( changed = False , host_name = host_name , host_port = host_port , host_type = host_type )
215+ if "{0}:{1}" .format (host_name , host_port ) in member ['host' ]:
216+ found_on_remove = True
219217 else :
220- if "{0}:{1}" .format (host_name , host_port ) not in member ['host' ] and member ['arbiterOnly' ]:
221- module .exit_json (changed = False , host_name = host_name , host_port = host_port , host_type = host_type )
218+ if "{0}:{1}" .format (host_name , host_port ) in member ['host' ] and member ['arbiterOnly' ]:
219+ found_on_remove = True
220+ if not found_on_remove and state == 'absent' :
221+ module .exit_json (changed = False , host_name = host_name , host_port = host_port , host_type = host_type )
222+
222223
223224def add_host (module , client , host_name , host_port , host_type , timeout = 180 , ** kwargs ):
224225 start_time = dtdatetime .now ()
@@ -257,13 +258,14 @@ def add_host(module, client, host_name, host_port, host_type, timeout=180, **kwa
257258
258259 cfg ['members' ].append (new_host )
259260 admin_db .command ('replSetReconfig' , cfg )
261+ module .exit_json (changed = True , host_name = host_name , host_port = host_port , host_type = host_type )
260262 return
261263 except (OperationFailure , AutoReconnect ) as e :
262264 if (dtdatetime .now () - start_time ).seconds > timeout :
263265 module .fail_json (msg = 'reached timeout while waiting for rs.reconfig(): %s' % str (e ))
264266 time .sleep (5 )
265267
266- def remove_host (module , client , host_name , timeout = 180 ):
268+ def remove_host (module , client , host_name , host_port , timeout = 180 ):
267269 start_time = dtdatetime .now ()
268270 while True :
269271 try :
@@ -281,12 +283,21 @@ def remove_host(module, client, host_name, timeout=180):
281283
282284 if len (cfg ['members' ]) == 1 :
283285 module .fail_json (msg = "You can't delete last member of replica set" )
286+
287+ removed_host = False
284288 for member in cfg ['members' ]:
285- if host_name in member ['host' ]:
289+ if host_name + ":" + host_port in member ['host' ]:
286290 cfg ['members' ].remove (member )
287- else :
288- fail_msg = "couldn't find member with hostname: {0} in replica set members list" .format (host_name )
289- module .fail_json (msg = fail_msg )
291+
292+ if remove_host :
293+ cfg ['version' ] += 1
294+ admin_db .command ('replSetReconfig' , cfg )
295+ module .exit_json (changed = True , host_name = host_name , host_port = host_port )
296+
297+ if not removed_host :
298+ fail_msg = "couldn't find member with hostname: {0} in replica set members list" .format (host_name )
299+ module .fail_json (msg = fail_msg )
300+
290301 except (OperationFailure , AutoReconnect ) as e :
291302 if (dtdatetime .now () - start_time ).seconds > timeout :
292303 module .fail_json (msg = 'reached timeout while waiting for rs.reconfig(): %s' % str (e ))
@@ -382,9 +393,10 @@ def main():
382393 ssl = module .params ['ssl' ]
383394 state = module .params ['state' ]
384395 priority = float (module .params ['priority' ])
385-
396+ hidden = module .params ['hidden' ]
397+ votes = module .params ['votes' ]
386398 replica_set_created = False
387-
399+
388400 try :
389401 if replica_set is None :
390402 module .fail_json (msg = 'replica_set parameter is required' )
@@ -398,7 +410,6 @@ def main():
398410 "serverselectiontimeoutms" : 5000 ,
399411 "replicaset" : replica_set ,
400412 }
401-
402413 if ssl :
403414 connection_params ["ssl" ] = ssl
404415 connection_params ["ssl_cert_reqs" ] = getattr (ssl_lib , module .params ['ssl_cert_reqs' ])
@@ -407,6 +418,38 @@ def main():
407418 authenticate (client , login_user , login_password )
408419 client ['admin' ].command ('replSetGetStatus' )
409420
421+ # Successful RS connection
422+ repl_set_status = None
423+ current_host_found = False
424+ try :
425+ repl_set_status = client ['admin' ].command ('replSetGetStatus' )
426+ current_host_found = host_name + ":" + host_port in [x ["name" ] for x in repl_set_status ["members" ]]
427+ except Exception as e :
428+ if not "no replset config has been received" in str (e ):
429+ raise e
430+
431+ if current_host_found and state == 'present' :
432+ requires_changes = False
433+ current_config = client ['admin' ].command ('replSetGetConfig' )
434+ for this_host in current_config ['config' ]['members' ]:
435+ if this_host ['host' ] == host_name + ":" + host_port :
436+ if priority != this_host ['priority' ]:
437+ requires_changes = True
438+ this_host ['priority' ] = priority
439+ if hidden != this_host ['hidden' ]:
440+ requires_changes = True
441+ this_host ['hidden' ] = hidden
442+ if votes != this_host ['votes' ]:
443+ requires_changes = True
444+ this_host ['votes' ] = votes
445+ if requires_changes :
446+ current_config ['config' ]['version' ] += 1
447+ client ['admin' ].command ('replSetReconfig' , current_config ['config' ])
448+ module .exit_json (changed = True , host_name = host_name , host_port = host_port , host_type = host_type )
449+ if not requires_changes :
450+ module .exit_json (changed = False , host_name = host_name , host_port = host_port , host_type = host_type )
451+
452+
410453 except ServerSelectionTimeoutError :
411454 try :
412455 connection_params = {
@@ -433,7 +476,8 @@ def main():
433476 wait_for_ok_and_master (module , connection_params )
434477 replica_set_created = True
435478 module .exit_json (changed = True , host_name = host_name , host_port = host_port , host_type = host_type )
436- except OperationFailure as e :
479+
480+ except OperationFailure as e :
437481 module .fail_json (msg = 'Unable to initiate replica set: %s' % str (e ))
438482 except ConnectionFailure as e :
439483 module .fail_json (msg = 'unable to connect to database: %s' % str (e ))
@@ -461,12 +505,13 @@ def main():
461505
462506 elif state == 'absent' :
463507 try :
464- remove_host (module , client , host_name )
508+ remove_host (module , client , host_name , host_port )
465509 except OperationFailure as e :
466510 module .fail_json (msg = 'Unable to remove member of replica set: %s' % str (e ))
467511
468- module .exit_json (changed = True , host_name = host_name , host_port = host_port , host_type = host_type )
512+ module .fail_json (msg = 'Operation error' )
513+
469514
470515# import module snippets
471516from ansible .module_utils .basic import *
472- main ()
517+ main ()
0 commit comments