diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index a47df42a1..6d173a237 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -60,7 +60,7 @@ from ipapython.ipautil import ( ) from ipapython.ssh import SSHPublicKey -from . import automount, ipadiscovery, ntpconf, sssd +from . import automount, ipadiscovery, timeconf, sssd from .ipachangeconf import IPAChangeConf NoneType = type(None) @@ -1989,8 +1989,8 @@ def install_check(options): if options.conf_ntp and not options.force_chrony: try: - ntpconf.check_timedate_services() - except ntpconf.NTPConflictingService as e: + timeconf.check_timedate_services() + except timeconf.NTPConflictingService as e: print("WARNING: chronyd time&date synchronization service will not" " be configured as") print("conflicting service ({}) is enabled".format( @@ -1998,10 +1998,10 @@ def install_check(options): print("Use --force-chrony option to disable it and force " "use of chronyd") print("") - + # TODO decide what to do if there is conflicting service # configuration of chrony is disabled in this case options.conf_ntp = False - except ntpconf.NTPConfigurationError: + except timeconf.NTPConfigurationError: pass if options.unattended and ( @@ -2345,18 +2345,21 @@ 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 +def sync_time(options, fstore, statestore, force): + """ + Will disable any other time synchronization service if there is + --force-chrony option set, and configure chrony with given ntp(chrony) + server and/or pool using Augeas in configure_chrony method. + If there is no option --ntp-server set IPADiscovery will try to find ntp + server in DNS records. + """ + # We assume that NTP servers are discoverable through SRV records in DNS. # disable other time&date services first - if options.force_chrony: - ntpconf.force_chrony(statestore) + if force: + timeconf.force_chrony(statestore) print("Synchronizing time") - print(" [1/1]: Configuring chrony client") logger.info('Synchronizing time with KDC...') if not options.ntp_servers: @@ -2367,37 +2370,37 @@ def sync_time(options, fstore, statestore): ntp_servers = options.ntp_servers if ntp_servers: - synced_time = ntpconf.configure_chrony(ntp_servers, options.ntp_pool, - fstore, statestore) + if timeconf.configure_chrony(ntp_servers, options.ntp_pool, + fstore, statestore): + print("Done Configuring chrony.") + else: + 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.") else: - synced_time = False + print("Warning: chrony not configured, using default configuration.") 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.") + "address was provided. Skipping chrony configuration, " + "default configuration will be used") def restore_time_sync(statestore, fstore): - chrony_configured = statestore.has_state('ntp') - if chrony_configured: - chrony_enabled = statestore.restore_state('ntp', 'enabled') + if statestore.has_state('chrony'): + chrony_enabled = statestore.restore_state('chrony', '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 + # Restore might fail due to missing file(s) in backup. + # One example is if the client was updated from a previous version + # not configured with chrony. In such a cast it is OK to fail. restored = fstore.restore_file(paths.CHRONY_CONF) - except Exception: - pass + except ValueError: # this will not handle possivble IOError + logger.debug("Configuration file %s was not restored.", + paths.CHRONY_CONF) if not chrony_enabled: services.knownservices.chronyd.stop() @@ -2406,7 +2409,7 @@ def restore_time_sync(statestore, fstore): services.knownservices.chronyd.restart() try: - ntpconf.restore_forced_chronyd(statestore) + timeconf.restore_forced_timeservices(statestore) except CalledProcessError as e: logger.error('Failed to restore time synchronization service: %s', e) @@ -2458,7 +2461,7 @@ def _install(options): if options.conf_ntp: # Attempt to sync time with NTP server (chrony). - sync_time(options, fstore, statestore) + sync_time(options, fstore, statestore, options.force_chrony) elif options.on_master: # If we're on master skipping the time sync here because it was done # in ipa-server-install @@ -3472,6 +3475,7 @@ class ClientInstallInterface(hostname_.HostNameInstallInterface, force_ntpd = knob( None, False, + deprecated=True, description="Stop and disable any time&date synchronization services " "besides ntpd.\n" "This option has been obsoleted by --force-chrony", diff --git a/ipaclient/install/ntpconf.py b/ipaclient/install/timeconf.py similarity index 91% rename from ipaclient/install/ntpconf.py rename to ipaclient/install/timeconf.py index fd4404724..d4e444691 100644 --- a/ipaclient/install/ntpconf.py +++ b/ipaclient/install/timeconf.py @@ -79,10 +79,10 @@ def configure_chrony(ntp_servers, ntp_pool=None, try: aug.save() - except Exception as e: + except IOError as e: logger.error("Augeas failed to configure file %s", chrony_conf) - except Exception as e: + except RuntimeError as e: logger.error("Configuration failed with: %s", e) finally: aug.close() @@ -101,20 +101,19 @@ def configure_chrony(ntp_servers, ntp_pool=None, # 3 attempts means if first immidiate attempt fails # there is 10s delay between next - cmd = [paths.CHRONYC, 'waitsync', str(sync_attempt_count)] + args = [paths.CHRONYC, 'waitsync', str(sync_attempt_count)] if debug: - cmd.append('-d') + args.append('-d') try: logger.info('Attempting to sync time using chronyd.') - ipautil.run(cmd) - logger.info('Time is in sync.') + ipautil.run(args) + logger.info('Time synchronization was successful.') return True - except ipautil.CalledProcessError as e: - if e.returncode is 1: - logger.warning('Process chronyc waitsync failed to sync time!') - logger.warning('Configuration of chrony was changed by installer.') + except ipautil.CalledProcessError: + logger.warning('Process chronyc waitsync failed to sync time!') + logger.warning('Configuration of chrony was changed by installer.') return False @@ -167,13 +166,13 @@ def force_chrony(statestore): instance.disable() -def restore_forced_chronyd(statestore): +def restore_forced_timeservices(statestore, skip_service='chronyd'): """ Restore from --force-chronyd installation and enable/start service that were disabled/stopped during installation """ for service in services.timedate_services: - if service == 'chronyd': + if service == skip_service: continue if statestore.has_state(service): instance = services.service(service, api) diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index 6eb338e03..06c621991 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -230,7 +230,6 @@ class BasePathNamespace(object): NAMED_PKCS11 = "/usr/sbin/named-pkcs11" CHRONYC = "/usr/bin/chronyc" CHRONYD = "/usr/sbin/chronyd" - CHRONY_HELPER = "/usr/libexec/chrony-helper" PKIDESTROY = "/usr/sbin/pkidestroy" PKISPAWN = "/usr/sbin/pkispawn" PKI = "/usr/bin/pki" diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py index 808516cce..c8382cbfb 100644 --- a/ipaserver/install/ipa_backup.py +++ b/ipaserver/install/ipa_backup.py @@ -162,7 +162,7 @@ class Backup(admintool.AdminTool): paths.IPA_CA_CRT, paths.IPA_DEFAULT_CONF, paths.DS_KEYTAB, - paths.NTP_CONF, + paths.CHRONY_CONF, paths.SMB_CONF, paths.SAMBA_KEYTAB, paths.DOGTAG_ADMIN_P12, diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 675c788a2..6a2b68750 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -31,7 +31,7 @@ from ipalib.util import ( validate_domain_name, no_matching_interface_for_ip_address_warning, ) -import ipaclient.install.ntpconf +import ipaclient.install.timeconf from ipaserver.install import ( adtrust, bindinstance, ca, dns, dsinstance, httpinstance, installutils, kra, krbinstance, @@ -413,13 +413,13 @@ def install_check(installer): if not options.no_ntp: try: - ipaclient.install.ntpconf.check_timedate_services() - except ipaclient.install.ntpconf.NTPConflictingService as e: - print("WARNING: conflicting time&date synchronization service '%s'" - " will be disabled" % e.conflicting_service) + ipaclient.install.timeconf.check_timedate_services() + except ipaclient.install.timeconf.NTPConflictingService as e: + print("WARNING: conflicting time&date synchronization service '{}'" + " will be disabled".format(e.conflicting_service)) print("in favor of chronyd") print("") - except ipaclient.install.ntpconf.NTPConfigurationError: + except ipaclient.install.timeconf.NTPConfigurationError: pass if not options.setup_dns and installer.interactive: @@ -766,7 +766,8 @@ def install(installer): # 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) + ipaclient.install.client.sync_time( + options, fstore, sstore, force=True) if options.dirsrv_cert_files: ds = dsinstance.DsInstance(fstore=fstore, @@ -1119,7 +1120,7 @@ def uninstall(installer): sstore._load() - ipaclient.install.ntpconf.restore_forced_chronyd(sstore) + ipaclient.install.timeconf.restore_forced_timeservices(sstore) # Clean up group_exists (unused since IPA 2.2, not being set since 4.1) sstore.restore_state("install", "group_exists") diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index 5472f869e..e221e6e36 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -23,7 +23,7 @@ from pkg_resources import parse_version import six from ipaclient.install.ipachangeconf import IPAChangeConf -import ipaclient.install.ntpconf +import ipaclient.install.timeconf from ipalib.install import certstore, sysrestore from ipalib.install.kinit import kinit_keytab from ipapython import ipaldap, ipautil @@ -581,12 +581,12 @@ def common_check(no_ntp): if not no_ntp: try: - ipaclient.install.ntpconf.check_timedate_services() - except ipaclient.install.ntpconf.NTPConflictingService as e: + ipaclient.install.timeconf.check_timedate_services() + except ipaclient.install.timeconf.NTPConflictingService as e: print("WARNING: conflicting time&date synchronization service " "'{svc}' will\nbe disabled in favor of chronyd\n" .format(svc=e.conflicting_service)) - except ipaclient.install.ntpconf.NTPConfigurationError: + except ipaclient.install.timeconf.NTPConfigurationError: pass @@ -1391,7 +1391,7 @@ def install(installer): if not promote and not options.no_ntp: # in DL1, chrony is already installed - ipaclient.install.ntpconf.force_chrony(sstore) + ipaclient.install.timeconf.force_chrony(sstore) try: if promote: diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py index cbf1417df..895555a3e 100644 --- a/ipaserver/install/server/upgrade.py +++ b/ipaserver/install/server/upgrade.py @@ -20,6 +20,7 @@ from ipalib.install import certmonger, sysrestore import SSSDConfig import ipalib.util import ipalib.errors +from ipaclient.install import timeconf from ipaclient.install.client import sssd_enable_service from ipaplatform import services from ipaplatform.tasks import tasks @@ -1593,6 +1594,41 @@ def enable_certauth(krb): aug.close() +def ntpd_cleanup(fqdn, fstore): + sstore = sysrestore.StateFile(paths.SYSRESTORE) + timeconf.restore_forced_timeservices(sstore, 'ntpd') + if sstore.has_state('ntp'): + instance = services.service('ntpd', api) + sstore.restore_state(instance.service_name, 'enabled') + sstore.restore_state(instance.service_name, 'running') + sstore.restore_state(instance.service_name, 'step-tickers') + try: + instance.disable() + instance.stop() + except Exception as e: + logger.info("Service ntpd was not disabled or stopped") + + ntpd_files = [paths.NTP_CONF, paths.NTP_STEP_TICKERS, paths.SYSCONFIG_NTPD] + for ntpd_file in ntpd_files: + try: + fstore.untrack_file(ntpd_file) + os.remove(ntpd_file) + except IOError: + logger.warning( + "No access to the %s, file could not be deleted.", ntpd_file) + except ValueError as e: + logger.warning("Error: %s", e) + + connection = api.Backend.ldap2 + try: + connection.delete_entry(DN(('cn', 'NTP'), ('cn', fqdn), + api.env.container_masters)) + except ipalib.errors.NotFound: + logger.warning("Warning: NTP service entry was not found in LDAP.") + + sysupgrade.set_upgrade_state('ntpd', 'ntpd_cleaned', True) + + def upgrade_configuration(): """ Execute configuration upgrade of the IPA services @@ -1613,6 +1649,9 @@ def upgrade_configuration(): if not ds_running: ds.start(ds_serverid) + if not sysupgrade.get_upgrade_state('ntpd', 'ntpd_cleaned'): + ntpd_cleanup(fqdn, fstore) + check_certs() auto_redirect = find_autoredirect(fqdn)