From 211f6c9046ab9b43c7f40e279db7c5595ae70bd1 Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Fri, 7 Dec 2012 16:44:32 +0100 Subject: Stop and disable conflicting time&date services Fedora 16 introduced chrony as default client time&date synchronization service: http://fedoraproject.org/wiki/Features/ChronyDefaultNTP Thus, there may be people already using chrony as their time and date synchronization service before installing IPA. However, installing IPA server or client on such machine may lead to unexpected behavior, as the IPA installer would configure ntpd and leave the machine with both ntpd and chronyd enabled. However, since the OS does not allow both chronyd and ntpd to be running concurrently and chronyd has the precedence, ntpd would not be run on that system at all. Make sure, that user is warned when trying to install IPA on such system and is given a possibility to either not to let IPA configure ntpd at all or to let the installer stop and disable chronyd. https://fedorahosted.org/freeipa/ticket/2974 --- install/tools/ipa-replica-install | 13 ++++++ install/tools/ipa-server-install | 17 ++++++++ ipa-client/ipa-install/ipa-client-install | 27 ++++++++++++ ipa-client/ipaclient/ntpconf.py | 68 +++++++++++++++++++++++++++++++ ipa-client/man/ipa-client-install.1 | 3 ++ ipapython/platform/base.py | 6 ++- ipapython/platform/fedora16.py | 5 ++- ipapython/platform/fedora18.py | 7 +++- ipapython/platform/redhat.py | 5 ++- 9 files changed, 146 insertions(+), 5 deletions(-) diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install index 7d7115cfd..b09cbca43 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install @@ -49,6 +49,7 @@ from ipapython import services as ipaservices from ipapython.ipa_log_manager import * from ipapython import dogtag from ipapython.dn import DN +import ipaclient.ntpconf log_file_name = "/var/log/ipareplica-install.log" CACERT = "/etc/ipa/ca.crt" @@ -438,6 +439,17 @@ def main(): check_dirsrv() + if options.conf_ntp: + try: + ipaclient.ntpconf.check_timedate_services() + except ipaclient.ntpconf.NTPConflictingService, e: + print "WARNING: conflicting time&date synchronization service '%s'" \ + " will" % e.conflicting_service + print "be disabled in favor of ntpd" + print "" + except ipaclient.ntpconf.NTPConfigurationError: + pass + # get the directory manager password dirman_password = options.password if not dirman_password: @@ -613,6 +625,7 @@ def main(): # Configure ntpd if options.conf_ntp: + ipaclient.ntpconf.force_ntpd(sstore) ntp = ntpinstance.NTPInstance() ntp.create_instance() diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install index 306d1e07b..dcf751904 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -68,6 +68,8 @@ from ipapython import services as ipaservices from ipapython.ipa_log_manager import * from ipapython.dn import DN +import ipaclient.ntpconf + pw_name = None uninstalling = False installation_cleanup = True @@ -507,6 +509,9 @@ def uninstall(): # ipa-client-install removes /etc/ipa/default.conf sstore._load() + + ipaclient.ntpconf.restore_forced_ntpd(sstore) + group_exists = sstore.restore_state("install", "group_exists") ipaservices.knownservices.ipa.disable() @@ -715,6 +720,17 @@ def main(): # Make sure the 389-ds ports are available check_dirsrv(options.unattended) + if options.conf_ntp: + try: + ipaclient.ntpconf.check_timedate_services() + except ipaclient.ntpconf.NTPConflictingService, e: + print "WARNING: conflicting time&date synchronization service '%s'" \ + " will be disabled" % e.conflicting_service + print "in favor of ntpd" + print "" + except ipaclient.ntpconf.NTPConfigurationError: + pass + realm_name = "" host_name = "" domain_name = "" @@ -907,6 +923,7 @@ def main(): # Configure ntpd if options.conf_ntp: + ipaclient.ntpconf.force_ntpd(sstore) ntp = ntpinstance.NTPInstance(fstore) if not ntp.is_configured(): ntp.create_instance() diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index 9e45589b8..975759169 100755 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -89,6 +89,9 @@ def parse_options(): basic_group.add_option("--ntp-server", dest="ntp_server", help="ntp server to use") basic_group.add_option("-N", "--no-ntp", action="store_false", help="do not configure ntp", default=True, dest="conf_ntp") + basic_group.add_option("", "--force-ntpd", dest="force_ntpd", + action="store_true", default=False, + help="Stop and disable any time&date synchronization services besides ntpd") basic_group.add_option("--ssh-trust-dns", dest="trust_sshfp", default=False, action="store_true", help="configure OpenSSH client to trust DNS SSHFP records") basic_group.add_option("--no-ssh", dest="conf_ssh", default=True, action="store_false", @@ -142,6 +145,9 @@ def parse_options(): if (options.server and not options.domain): parser.error("--server cannot be used without providing --domain") + if options.force_ntpd and not options.conf_ntp: + parser.error("--force-ntpd cannot be used together with --no-ntp") + return safe_opts, options def logging_setup(options): @@ -519,6 +525,8 @@ def uninstall(options, env): if restored: ipaservices.knownservices.ntpd.restart() + ipaclient.ntpconf.restore_forced_ntpd(statestore) + if was_sshd_configured and ipaservices.knownservices.sshd.is_running(): ipaservices.knownservices.sshd.restart() @@ -1270,6 +1278,22 @@ def install(options, env, fstore, statestore): cli_domain_source = 'Unknown source' cli_server_source = 'Unknown source' + if options.conf_ntp and not options.on_master and not options.force_ntpd: + try: + ipaclient.ntpconf.check_timedate_services() + except ipaclient.ntpconf.NTPConflictingService, e: + print "WARNING: ntpd time&date synchronization service will not" \ + " be configured as" + print "conflicting service (%s) is enabled" % e.conflicting_service + print "Use --force-ntpd option to disable it and force configuration" \ + " of ntpd" + print "" + + # configuration of ntpd is disabled in this case + options.conf_ntp = False + except ipaclient.ntpconf.NTPConfigurationError: + pass + if options.unattended and (options.password is None and options.principal is None and options.prompt_password is False) and not options.on_master: root_logger.error("One of password and principal are required.") return CLIENT_INSTALL_ERROR @@ -1884,6 +1908,9 @@ def install(options, env, fstore, statestore): "/etc/ldap.conf failed: %s", str(e)) if options.conf_ntp and not options.on_master: + # disable other time&date services first + if options.force_ntpd: + ipaclient.ntpconf.force_ntpd(statestore) if options.ntp_server: ntp_server = options.ntp_server else: diff --git a/ipa-client/ipaclient/ntpconf.py b/ipa-client/ipaclient/ntpconf.py index 6e4173145..eb9afdeee 100644 --- a/ipa-client/ipaclient/ntpconf.py +++ b/ipa-client/ipaclient/ntpconf.py @@ -21,6 +21,7 @@ from ipapython import ipautil from ipapython import services as ipaservices import shutil import os +import sys ntp_conf = """# Permit time synchronization with our time source, but do not # permit the source to query or modify the service on this system. @@ -154,3 +155,70 @@ def synconce_ntp(server_fqdn): except: pass return False + +class NTPConfigurationError(Exception): + pass + +class NTPConflictingService(NTPConfigurationError): + def __init__(self, message='', conflicting_service=None): + super(NTPConflictingService, self).__init__(self, message) + self.conflicting_service = conflicting_service + +def check_timedate_services(): + """ + System may contain conflicting services used for time&date synchronization. + As IPA server/client supports only ntpd, make sure that other services are + not enabled to prevent conflicts. For example when both chronyd and ntpd + are enabled, systemd would always start only chronyd to manage system + time&date which would make IPA configuration of ntpd ineffective. + + Reference links: + https://fedorahosted.org/freeipa/ticket/2974 + http://fedoraproject.org/wiki/Features/ChronyDefaultNTP + """ + for service in ipaservices.timedate_services: + if service == 'ntpd': + continue + # Make sure that the service is not enabled + service = ipaservices.service(service) + if service.is_enabled() or service.is_running(): + raise NTPConflictingService(conflicting_service=service.service_name) + +def force_ntpd(statestore): + """ + Force ntpd configuration and disable and stop any other conflicting + time&date service + """ + for service in ipaservices.timedate_services: + if service == 'ntpd': + continue + service = ipaservices.service(service) + enabled = service.is_enabled() + running = service.is_running() + + if enabled or running: + statestore.backup_state(service.service_name, 'enabled', enabled) + statestore.backup_state(service.service_name, 'running', running) + + if running: + service.stop() + + if enabled: + service.disable() + +def restore_forced_ntpd(statestore): + """ + Restore from --force-ntpd installation and enable/start service that were + disabled/stopped during installation + """ + for service in ipaservices.timedate_services: + if service == 'ntpd': + continue + if statestore.has_state(service): + service = ipaservices.service(service) + enabled = statestore.restore_state(service.service_name, 'enabled') + running = statestore.restore_state(service.service_name, 'running') + if enabled: + service.enable() + if running: + service.start() diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1 index 382d4872f..abd74666e 100644 --- a/ipa-client/man/ipa-client-install.1 +++ b/ipa-client/man/ipa-client-install.1 @@ -71,6 +71,9 @@ Configure ntpd to use this NTP server. \fB\-N\fR, \fB\-\-no\-ntp\fR Do not configure or enable NTP. .TP +\fB\-\-force\-ntpd\fR +Stop and disable any time&date synchronization services besides ntpd. +.TP \fB\-\-ssh\-trust\-dns\fR Configure OpenSSH client to trust DNS SSHFP records. .TP diff --git a/ipapython/platform/base.py b/ipapython/platform/base.py index 41a9c83e7..e2aa33faf 100644 --- a/ipapython/platform/base.py +++ b/ipapython/platform/base.py @@ -27,7 +27,11 @@ import os wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc', 'messagebus', 'nslcd', 'nscd', 'ntpd', 'portmap', 'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd', - 'rpcidmapd', 'pki_tomcatd', 'pki-cad'] + 'rpcidmapd', 'pki_tomcatd', 'pki-cad', 'chronyd'] + +# System may support more time&date services. FreeIPA supports ntpd only, other +# services will be disabled during IPA installation +timedate_services = ['ntpd', 'chronyd'] # The common ports for these services. This is used to wait for the diff --git a/ipapython/platform/fedora16.py b/ipapython/platform/fedora16.py index 8609e4c4b..628cad13d 100644 --- a/ipapython/platform/fedora16.py +++ b/ipapython/platform/fedora16.py @@ -44,7 +44,10 @@ from ipalib import api # and restorecon is installed. __all__ = ['authconfig', 'service', 'knownservices', 'backup_and_replace_hostname', 'restore_context', 'check_selinux_status', - 'restore_network_configuration'] + 'restore_network_configuration', 'timedate_services'] + +# Just copy a referential list of timedate services +timedate_services = list(base.timedate_services) # For beginning just remap names to add .service # As more services will migrate to systemd, unit names will deviate and diff --git a/ipapython/platform/fedora18.py b/ipapython/platform/fedora18.py index c6d32866f..d12bdcad5 100644 --- a/ipapython/platform/fedora18.py +++ b/ipapython/platform/fedora18.py @@ -23,7 +23,7 @@ import socket import os from ipapython import ipautil -from ipapython.platform import fedora16 +from ipapython.platform import fedora16, base # All what we allow exporting directly from this module # Everything else is made available through these symbols when they are @@ -44,7 +44,10 @@ from ipapython.platform import fedora16 # and restorecon is installed. __all__ = ['authconfig', 'service', 'knownservices', 'backup_and_replace_hostname', 'restore_context', 'check_selinux_status', - 'restore_network_configuration'] + 'restore_network_configuration', 'timedate_services'] + +# Just copy a referential list of timedate services +timedate_services = list(base.timedate_services) def backup_and_replace_hostname(fstore, statestore, hostname): old_hostname = socket.gethostname() diff --git a/ipapython/platform/redhat.py b/ipapython/platform/redhat.py index 389785c7b..274062e46 100644 --- a/ipapython/platform/redhat.py +++ b/ipapython/platform/redhat.py @@ -52,7 +52,10 @@ from ipalib import api # and restorecon is installed. __all__ = ['authconfig', 'service', 'knownservices', 'backup_and_replace_hostname', 'restore_context', 'check_selinux_status', - 'restore_network_configuration'] + 'restore_network_configuration', 'timedate_services'] + +# Just copy a referential list of timedate services +timedate_services = list(base.timedate_services) class RedHatService(base.PlatformService): def __wait_for_open_ports(self, instance_name=""): -- cgit