267267 default: 1
268268 choices: [ 0, 1, 2, 3, 4, 5 ]
269269 type: int
270+ preserve:
271+ description: Preserve the current DNS entries instead of overriding them.
272+ required: false
273+ default: false
274+ type: bool
270275"""
271276
272277EXAMPLES = """
371376 infra_host_ttl = dict (default = 900 , type = 'int' , choices = [60 , 120 , 300 , 600 , 900 ]),
372377 infra_cache_numhosts = dict (default = 10000 , type = 'int' , choices = [1000 , 5000 , 10000 , 20000 , 50000 , 100000 , 200000 ]),
373378 unwanted_reply_threshold = dict (default = "disabled" , type = 'str' , choices = ["disabled" , "5000000" , "10000000" , "20000000" , "40000000" , "50000000" ]),
374- log_verbosity = dict (default = 1 , type = 'int' , choices = [0 , 1 , 2 , 3 , 4 , 5 ])
379+ log_verbosity = dict (default = 1 , type = 'int' , choices = [0 , 1 , 2 , 3 , 4 , 5 ]),
380+ preserve = dict (default = False , type = 'bool' ),
375381 # TODO: Disable Auto-added Access Control
376382 # TODO: Disable Auto-added Host Entries
377383 # TODO: Experimental Bit 0x20 Support
@@ -415,13 +421,68 @@ def _params_to_obj(self):
415421 params = self .params
416422
417423 obj = dict ()
418-
424+ # Initialize with existing configuration_merg
425+ if self .root_elt is not None :
426+ # Preserve existing hosts
427+ existing_hosts = []
428+ # Preserve existing custom options
429+ existing_custom_options = []
430+ custom_options_elt = self .root_elt .find ("custom_options" )
431+
432+ if custom_options_elt is not None and custom_options_elt .text :
433+ # Decode the base64-encoded custom options
434+ decoded_custom_options = base64 .b64decode (custom_options_elt .text ).decode ('utf-8' )
435+ # Split into lines for comparison
436+ existing_custom_options = [line .strip () for line in decoded_custom_options .strip ().split ("\n " )]
437+
438+ if params .get ("custom_options" ):
439+ new_custom_options = [line .strip () for line in params ["custom_options" ].strip ().split ("\n " )]
440+ merged_custom_options = existing_custom_options .copy ()
441+ for option in new_custom_options :
442+ if "view:" or "server:" in option :
443+ merged_custom_options .append (option )
444+ elif option not in existing_custom_options :
445+ merged_custom_options .append (option )
446+ else :
447+ pass
448+
449+ custom_opts_base64 = base64 .b64encode (bytes ("\n " .join (merged_custom_options ), "utf-8" )).decode ()
450+
451+ else :
452+ # If no new custom options are provided, retain the existing ones
453+ custom_opts_base64 = custom_options_elt .text if custom_options_elt is not None else ""
454+
455+ if params .get ("preserve" ):
456+ for host_elt in self .root_elt .findall ("hosts" ):
457+ host_entry = {}
458+ for child in host_elt :
459+ if child .tag == "aliases" and child .text is not None :
460+ # Handle aliases as a string if it's not an XML element
461+ host_entry ["aliases" ] = child .text
462+ else :
463+ host_entry [child .tag ] = child .text
464+ existing_hosts .append (host_entry )
465+ existing_hosts .extend (params .get ("hosts" ))
466+ # exit()
467+
468+ # Preserve existing domain overrides
469+ existing_overrides = []
470+ for override_elt in self .root_elt .findall ("domainoverrides" ):
471+ override_entry = {}
472+ for child in override_elt :
473+ override_entry [child .tag ] = child .text
474+ existing_overrides .append (override_entry )
475+
476+ if existing_hosts :
477+ obj ["hosts" ] = existing_hosts
478+ if existing_overrides :
479+ obj ["domainoverrides" ] = existing_overrides
480+
419481 if params ["state" ] == "present" :
420482
421483 obj ["enable" ] = ""
422484 obj ["active_interface" ] = "," .join (self .get_interface_by_display_name (x ) for x in params ["active_interface" ])
423485 obj ["outgoing_interface" ] = "," .join (self .get_interface_by_display_name (x ) for x in params ["outgoing_interface" ])
424- obj ["custom_options" ] = base64 .b64encode (bytes (params ['custom_options' ], 'utf-8' )).decode ()
425486 self ._get_ansible_param_bool (obj , "hideidentity" , value = "" )
426487 self ._get_ansible_param_bool (obj , "hideversion" , value = "" )
427488 self ._get_ansible_param_bool (obj , "dnssecstripped" , value = "" )
@@ -451,8 +512,39 @@ def _params_to_obj(self):
451512 self ._get_ansible_param (obj , "infra_cache_numhosts" )
452513 self ._get_ansible_param (obj , "unwanted_reply_threshold" )
453514 self ._get_ansible_param (obj , "log_verbosity" )
454- self ._get_ansible_param (obj , "hosts" )
455515 self ._get_ansible_param (obj , "domainoverrides" )
516+ obj ["custom_options" ] = base64 .b64encode (bytes (params ['custom_options' ], 'utf-8' )).decode ()
517+ if params .get ("preserve" ):
518+ obj ["hosts" ] = existing_hosts
519+ if existing_overrides :
520+ obj ["domainoverrides" ] = existing_overrides
521+ if existing_custom_options :
522+ obj ["custom_options" ] = custom_opts_base64
523+
524+ # Append new hosts if provided
525+ if params .get ("hosts" ):
526+ if "hosts" not in obj :
527+ obj ["hosts" ] = []
528+
529+ # Process new hosts
530+ for new_host in params ["hosts" ]:
531+ # Format aliases for the new host
532+ if new_host .get ("aliases" ):
533+ new_host ["aliases" ] = {"item" : new_host ["aliases" ]}
534+ else :
535+ new_host ["aliases" ] = "\n \t \t \t "
536+
537+ existing_host_index = self ._find_host_index (obj , new_host )
538+
539+ if existing_host_index is not None :
540+ obj ["hosts" ][existing_host_index ] = new_host
541+ else :
542+ obj ["hosts" ].append (new_host )
543+ # Append new domain overrides if provided
544+ if params .get ("domainoverrides" ):
545+ if "domainoverrides" not in obj :
546+ obj ["domainoverrides" ] = []
547+ obj ["domainoverrides" ].extend (params ["domainoverrides" ])
456548
457549 if obj ["active_interface" ] != "all" :
458550 obj ["active_interface" ] += ",lo0"
@@ -465,11 +557,17 @@ def _params_to_obj(self):
465557 "item" : tmp_aliases
466558 }
467559 else :
468- # Default is an empty element
469560 host ["aliases" ] = ""
470-
471561 return obj
472562
563+ def _find_host_index (self , obj , new_host ):
564+ for index , nested_dict in enumerate (obj ["hosts" ]):
565+ existing_host = f"{ nested_dict .get ('host' )} .{ nested_dict .get ('domain' )} "
566+ new_host_fqdn = f"{ new_host .get ('host' )} .{ new_host .get ('domain' )} "
567+ if existing_host == new_host_fqdn :
568+ return index
569+ return None
570+
473571 def _validate_params (self ):
474572 """ do some extra checks on input parameters """
475573 params = self .params
@@ -567,7 +665,6 @@ def _log_fields(self, before=None):
567665 # todo: hosts and domainoverrides is not logged
568666 return values
569667
570-
571668def main ():
572669 module = AnsibleModule (
573670 argument_spec = DNS_RESOLVER_ARGUMENT_SPEC ,
0 commit comments