diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index be2788298..4bdb99415 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -1987,7 +1987,7 @@ def install_check(options): "using 'ipa-client-install --uninstall'.") raise ScriptError(rval=CLIENT_ALREADY_CONFIGURED) - if options.conf_ntp and not options.on_master and not options.force_chrony: + if options.conf_ntp and not options.force_chrony: try: ntpconf.check_timedate_services() except ntpconf.NTPConflictingService as e: @@ -2345,6 +2345,71 @@ def update_ipa_nssdb(): (nickname, sys_db.secdir, e)) +def sync_time(options, fstore, statestore): + # 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 + + # disable other time&date services first + if options.force_chrony: + ntpconf.force_chrony(statestore) + + print("Synchronizing time") + print(" [1/1]: Configuring chrony client") + logger.info('Synchronizing time with KDC...') + + if not options.ntp_servers: + ds = ipadiscovery.IPADiscovery() + ntp_servers = ds.ipadns_search_srv(cli_domain, '_ntp._udp', + None, break_on_first=False) + else: + ntp_servers = options.ntp_servers + + if ntp_servers: + synced_time = ntpconf.configure_chrony(ntp_servers, fstore, statestore) + else: + synced_time = False + logger.warning("No SRV records of NTP servers found nor NTP server " + "address was privided. Skipping chrony configuration") + + if not synced_time: + print("Warning: IPA Server was unable to sync time with chrony!") + print(" Time synchronization is required " + "for IPA Server to work correctly") + logger.warning( + "Unable to sync time with chrony server, assuming the time " + "is in sync. Please check that 123 UDP port is opened, " + "and any time server is on network.") + + +def restore_time_sync(statestore, fstore): + chrony_configured = statestore.has_state('ntp') + if chrony_configured: + chrony_enabled = statestore.restore_state('ntp', 'enabled') + restored = False + + try: + # Restore might fail due to file missing in backup + # the reason for it might be that freeipa-client was updated + # to this version but not unenrolled/enrolled again + # In such case it is OK to fail + restored = fstore.restore_file(paths.CHRONY_CONF) + except Exception: + pass + + if not chrony_enabled: + services.knownservices.chronyd.stop() + services.knownservices.chronyd.disable() + elif restored: + services.knownservices.chronyd.restart() + + try: + ntpconf.restore_forced_chronyd(statestore) + except CalledProcessError as e: + logger.error('Failed to restore time synchronization service: %s', e) + + def install(options): try: _install(options) @@ -2390,42 +2455,14 @@ def _install(options): tasks.backup_hostname(fstore, statestore) tasks.set_hostname(options.hostname) - if 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 - - # disable other time&date services first - if options.force_chrony: - ntpconf.force_chrony(statestore) - - logger.info('Synchronizing time with KDC...') - - if not options.ntp_servers: - ds = ipadiscovery.IPADiscovery() - ntp_servers = ds.ipadns_search_srv(cli_domain, '_ntp._udp', - None, break_on_first=False) - - if not ntp_servers: - logger.warning("No SRV records of NTP servers found. IPA " - "server address will be used") - ntp_servers = cli_server - else: - ntp_servers = options.ntp_servers - - synced_time = ntpconf.configure_chrony(ntp_servers, fstore, - statestore, options.debug) - - if not synced_time: - logger.warning( - "Unable to sync time with chrony server, assuming the time " - "is in sync. Please check that 123 UDP port is opened, " - "and any time server is on network.") - else: - logger.info('Skipping synchronizing time with chrony server.') + if options.conf_ntp: + # Attempt to 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.") if not options.unattended: if (options.principal is None and options.password is None and @@ -3241,31 +3278,7 @@ def uninstall(options): service.service_name ) - chrony_configured = statestore.has_state('ntp') - if chrony_configured: - chrony_enabled = statestore.restore_state('ntp', 'enabled') - restored = False - - try: - # Restore might fail due to file missing in backup - # the reason for it might be that freeipa-client was updated - # to this version but not unenrolled/enrolled again - # In such case it is OK to fail - restored = fstore.restore_file(paths.CHRONY_CONF) - except Exception: - pass - - if not chrony_enabled: - services.knownservices.chronyd.stop() - services.knownservices.chronyd.disable() - else: - if restored: - services.knownservices.chronyd.restart() - - try: - ntpconf.restore_forced_chronyd(statestore) - except CalledProcessError as e: - logger.error('Failed to restore time synchronization service: %s', e) + restore_time_sync(statestore, fstore) if was_sshd_configured and services.knownservices.sshd.is_running(): services.knownservices.sshd.restart() @@ -3444,7 +3457,7 @@ class ClientInstallInterface(hostname_.HostNameInstallInterface, ntp_servers = enroll_only(ntp_servers) no_ntp = knob( - None, True, + None, description="do not configure ntp", cli_names=[None, '-N'], ) @@ -3539,6 +3552,10 @@ class ClientInstallInterface(hostname_.HostNameInstallInterface, raise RuntimeError( "--force-chrony cannot be used together with --no-ntp") + if self.ntp_servers and self.no_ntp: + raise RuntimeError( + "--ntp-server cannot be used together with --no-ntp") + if self.no_nisdomain and self.nisdomain: raise RuntimeError( "--no-nisdomain cannot be used together with --nisdomain") diff --git a/ipaclient/install/ntpconf.py b/ipaclient/install/ntpconf.py index a9f05687d..5ed2a13f3 100644 --- a/ipaclient/install/ntpconf.py +++ b/ipaclient/install/ntpconf.py @@ -103,10 +103,12 @@ def configure_chrony(ntp_servers, fstore=None, sysstore=None, debug=False): try: logger.info('Attempting to sync time using chronyd.') ipautil.run(cmd) + logger.info('Time is in sync.') return True except ipautil.CalledProcessError as e: if e.returncode is 1: - logger.debug('Process chronyc waitsync failed to sync time') + logger.warning('Process chronyc waitsync failed to sync time!') + logger.warning('Configuration of chrony was changed by installer.') return False diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py index 9b796899a..7dc7d6dbd 100644 --- a/ipaserver/install/server/__init__.py +++ b/ipaserver/install/server/__init__.py @@ -168,7 +168,6 @@ class ServerInstallInterface(ServerCertificateInstallInterface, kinit_attempts = 1 fixed_primary = True - ntp_servers = None force_chrony = False permit = False enable_dns_updates = False diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 58aaedf5a..675c788a2 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -761,6 +761,13 @@ def install(installer): # Create a directory server instance if not options.external_cert_files: + # We have to sync time before certificate handling on master. + # As chrony configuration is moved from client here, unconfiguration of + # chrony will be handled here in uninstall() method as well by invoking + # the ipa-server-install --uninstall + if not options.no_ntp: + ipaclient.install.client.sync_time(options, fstore, sstore) + if options.dirsrv_cert_files: ds = dsinstance.DsInstance(fstore=fstore, domainlevel=options.domainlevel, @@ -906,7 +913,7 @@ def install(installer): try: args = [paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended", "--domain", domain_name, "--server", host_name, - "--realm", realm_name, "--hostname", host_name] + "--realm", realm_name, "--hostname", host_name, "--no-ntp"] if options.no_dns_sshfp: args.append("--no-dns-sshfp") if options.ssh_trust_dns: @@ -1082,6 +1089,8 @@ def uninstall(installer): except Exception: pass + ipaclient.install.client.restore_time_sync(sstore, fstore) + kra.uninstall() ca.uninstall()