From 4063b6caa3012f396ac759d6fa2bf7b14418c8d5 Mon Sep 17 00:00:00 2001 From: Thomas Woerner <twoerner@redhat.com> Date: Thu, 21 Jun 2018 13:04:32 +0200 Subject: [PATCH] ipaclient: Add support for IPA 4.7 (4.6.90-pre2) With IPA 4.7 bigger changes have been introduced Changes: - Use of timeconf and chrony instead of ntpconf and ntpd. - A new option ntp_pool has been introduced. --- module_utils/ansible_ipa_client.py | 19 +++- roles/ipaclient/library/ipadiscovery.py | 138 +++++++++++++++++------- roles/ipaclient/tasks/install.yml | 1 + 3 files changed, 119 insertions(+), 39 deletions(-) diff --git a/module_utils/ansible_ipa_client.py b/module_utils/ansible_ipa_client.py index 0839770c..44371792 100644 --- a/module_utils/ansible_ipa_client.py +++ b/module_utils/ansible_ipa_client.py @@ -160,9 +160,24 @@ if NUM_VERSION >= 40400: unicode = str try: - from ipaclient.install import ntpconf + from ipaclient.install import timeconf + time_service = "chronyd" except ImportError: - from ipaclient import ntpconf + try: + from ipaclient.install import ntpconf as timeconf + except ImportError: + from ipaclient import ntpconf as timeconf + time_service = "ntpd" + + try: + from ipaclient.install.client import sync_time + except ImportError: + sync_time = None + + try: + from ipaclient.install.client import check_ldap_conf + except ImportError: + check_ldap_conf = None logger = logging.getLogger("ipa-client-install") diff --git a/roles/ipaclient/library/ipadiscovery.py b/roles/ipaclient/library/ipadiscovery.py index e98ab164..24f2e12e 100644 --- a/roles/ipaclient/library/ipadiscovery.py +++ b/roles/ipaclient/library/ipadiscovery.py @@ -63,12 +63,23 @@ options: required: false type: list default: [] + ntp_pool: + description: ntp server pool to use + required: false no_ntp: description: Do not sync time and do not detect time servers required: false default: false type: bool default: no + no_nisdomain: + description: Do not configure NIS domain name + required: false + type: bool + default: no + nisdomain: + description: NIS domain name + required: false author: - Thomas Woerner ''' @@ -223,20 +234,30 @@ def main(): ca_cert_file=dict(required=False), on_master=dict(required=False, type='bool', default=False), ntp_servers=dict(required=False, type='list', default=[]), + ntp_pool=dict(required=False), no_ntp=dict(required=False, type='bool', default=False), + #no_nisdomain=dict(required=False, type='bool', default='no'), + #nisdomain=dict(required=False), ), supports_check_mode = True, ) module._ansible_debug = True - opt_domain = module.params.get('domain') - opt_servers = module.params.get('servers') - opt_realm = module.params.get('realm') - opt_hostname = module.params.get('hostname') - opt_ca_cert_file = module.params.get('ca_cert_file') - opt_on_master = module.params.get('on_master') - opt_ntp_servers = module.params.get('ntp_servers') - opt_no_ntp = module.params.get('no_ntp') + options.domain = module.params.get('domain') + options.servers = module.params.get('servers') + options.realm = module.params.get('realm') + options.hostname = module.params.get('hostname') + options.ca_cert_file = module.params.get('ca_cert_file') + options.on_master = module.params.get('on_master') + options.ntp_servers = module.params.get('ntp_servers') + options.ntp_pool = module.params.get('ntp_pool') + options.no_ntp = module.params.get('no_ntp') + options.conf_ntp = not options.no_ntp + #options.no_nisdomain = module.params.get('no_nisdomain') + #options.nisdomain = module.params.get('nisdomain') + #options.ip_addresses + #options.all_ip_addresses + #options.enable_dns_updates hostname = None hostname_source = None @@ -248,8 +269,34 @@ def main(): client_domain = None cli_basedn = None - if opt_hostname: - hostname = opt_hostname + fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) + statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) + + if options.ntp_servers and options.no_ntp: + module.fail_json( + "--ntp-server cannot be used together with --no-ntp") + + if options.ntp_pool and options.no_ntp: + module.fail_json( + "--ntp-pool cannot be used together with --no-ntp") + + #if options.no_nisdomain and options.nisdomain: + # module.fail_json( + # "--no-nisdomain cannot be used together with --nisdomain") + + #if options.ip_addresses: + # if options.enable_dns_updates: + # module.fail_json( + # "--ip-addresses cannot be used together with" + # " --enable-dns-updates") + + # if options.all_ip_addresses: + # module.fail_json( + # "--ip-address cannot be used together with" + # "--all-ip-addresses") + + if options.hostname: + hostname = options.hostname hostname_source = 'Provided as option' else: hostname = socket.getfqdn() @@ -263,25 +310,25 @@ def main(): msg="Invalid hostname, '%s' must not be used." % hostname) # Get domain from first server if domain is not set, but there are servers - if opt_domain is None and len(opt_servers) > 0: - opt_domain = opt_servers[0][opt_servers[0].find(".")+1:] + if options.domain is None and len(options.servers) > 0: + options.domain = options.servers[0][options.servers[0].find(".")+1:] # Create the discovery instance ds = ipadiscovery.IPADiscovery() ret = ds.search( - domain=opt_domain, - servers=opt_servers, - realm=opt_realm, + domain=options.domain, + servers=options.servers, + realm=options.realm, hostname=hostname, - ca_cert_path=get_cert_path(opt_ca_cert_file)) + ca_cert_path=get_cert_path(options.ca_cert_file)) - if opt_servers and ret != 0: + if options.servers and ret != 0: # There is no point to continue with installation as server list was # passed as a fixed list of server and thus we cannot discover any # better result module.fail_json(msg="Failed to verify that %s is an IPA Server." % \ - ', '.join(opt_servers)) + ', '.join(options.servers)) if ret == ipadiscovery.BAD_HOST_CONFIG: module.fail_json(msg="Can't get the fully qualified name of this host") @@ -301,8 +348,8 @@ def main(): module.log("No IPA server found") else: module.log("Domain not found") - if opt_domain: - cli_domain = opt_domain + if options.domain: + cli_domain = options.domain cli_domain_source = 'Provided as option' else: module.fail_json( @@ -310,9 +357,9 @@ def main(): ret = ds.search( domain=cli_domain, - servers=opt_servers, + servers=options.servers, hostname=hostname, - ca_cert_path=get_cert_path(opt_ca_cert_file)) + ca_cert_path=get_cert_path(options.ca_cert_file)) if not cli_domain: if ds.domain: @@ -325,8 +372,8 @@ def main(): if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \ or not ds.server: module.debug("IPA Server not found") - if opt_servers: - cli_server = opt_servers + if options.servers: + cli_server = options.servers cli_server_source = 'Provided as option' else: module.fail_json(msg="Unable to find IPA Server to join") @@ -335,12 +382,12 @@ def main(): domain=cli_domain, servers=cli_server, hostname=hostname, - ca_cert_path=get_cert_path(opt_ca_cert_file)) + ca_cert_path=get_cert_path(options.ca_cert_file)) else: # Only set dnsok to True if we were not passed in one or more servers # and if DNS discovery actually worked. - if not opt_servers: + if not options.servers: (server, domain) = ds.check_domain( ds.domain, set(), "Validating DNS Discovery") if server and domain: @@ -353,11 +400,11 @@ def main(): "Using servers from command line, disabling DNS discovery") if not cli_server: - if opt_servers: + if options.servers: cli_server = ds.servers cli_server_source = 'Provided as option' module.debug( - "will use provided server: %s" % ', '.join(opt_servers)) + "will use provided server: %s" % ', '.join(options.servers)) elif ds.server: cli_server = ds.servers cli_server_source = ds.server_source @@ -392,11 +439,11 @@ def main(): cli_realm_source = ds.realm_source module.debug("will use discovered realm: %s" % cli_realm) - if opt_realm and opt_realm != cli_realm: + if options.realm and options.realm != cli_realm: module.fail_json( msg= "The provided realm name [%s] does not match discovered one [%s]" % - (opt_realm, cli_realm)) + (options.realm, cli_realm)) cli_basedn = str(ds.basedn) cli_basedn_source = ds.basedn_source @@ -432,14 +479,33 @@ def main(): "installation may fail.") break - if not opt_on_master and not opt_no_ntp: - if len(opt_ntp_servers) < 1: + ntp_servers = [ ] + if sync_time is not None: + if options.conf_ntp: + # Attempt to configure and sync time with NTP server (chrony). + sync_time(options, fstore, statestore) + elif options.on_master: + # If we're on master skipping the time sync here because it was done + # in ipa-server-install + logger.info("Skipping attempt to configure and synchronize time with" + " chrony server as it has been already done on master.") + else: + logger.info("Skipping chrony configuration") + + elif not options.on_master and options.conf_ntp: + # Attempt to sync time with IPA server. + # If we're skipping NTP configuration, we also skip the time sync here. + # We assume that NTP servers are discoverable through SRV records + # in the DNS. + # If that fails, we try to sync directly with IPA server, + # assuming it runs NTP + if len(options.ntp_servers) < 1: # Detect NTP servers ds = ipadiscovery.IPADiscovery() ntp_servers = ds.ipadns_search_srv(cli_domain, '_ntp._udp', None, break_on_first=False) else: - ntp_servers = opt_ntp_servers + ntp_servers = options.ntp_servers # Attempt to sync time: # At first with given or dicovered time servers. If no ntp @@ -449,15 +515,13 @@ def main(): synced_ntp = False # use user specified NTP servers if there are any for s in ntp_servers: - synced_ntp = ntpconf.synconce_ntp(s, False) + synced_ntp = timconf.synconce_ntp(s, False) if synced_ntp: break if not synced_ntp and not ntp_servers: - synced_ntp = ntpconf.synconce_ntp(cli_server[0], False) + synced_ntp = timeconf.synconce_ntp(cli_server[0], False) if not synced_ntp: module.warn("Unable to sync time with NTP server") - else: - ntp_servers = [ ] # Check if ipa client is already configured if is_client_configured(): diff --git a/roles/ipaclient/tasks/install.yml b/roles/ipaclient/tasks/install.yml index 78724c7c..1730b5ac 100644 --- a/roles/ipaclient/tasks/install.yml +++ b/roles/ipaclient/tasks/install.yml @@ -30,6 +30,7 @@ ca_cert_file: "{{ ipaclient_ca_cert_file | default(omit) }}" on_master: "{{ ipaclient_on_master }}" ntp_servers: "{{ ipaclient_ntp_servers | default([]) }}" + ntp_pool: "{{ ipaclient_ntp_pool | default(omit) }}" no_ntp: "{{ ipaclient_no_ntp }}" register: ipadiscovery -- GitLab