Adding method to ipa-server-upgrade to cleanup ntpd

Removing ntpd configuration files and entry from LDAP.

Add parameter and rename method for restoring forced time
services. Addressing some requests for change too.

Remove unused path for chrony-helper.

Resolves: https://pagure.io/freeipa/issue/7024
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Tibor Dudlák 2018-03-13 14:41:20 +01:00 committed by Rob Crittenden
parent 194518f11f
commit 5d9c749e83
7 changed files with 106 additions and 64 deletions

View File

@ -60,7 +60,7 @@ from ipapython.ipautil import (
) )
from ipapython.ssh import SSHPublicKey from ipapython.ssh import SSHPublicKey
from . import automount, ipadiscovery, ntpconf, sssd from . import automount, ipadiscovery, timeconf, sssd
from .ipachangeconf import IPAChangeConf from .ipachangeconf import IPAChangeConf
NoneType = type(None) NoneType = type(None)
@ -1989,8 +1989,8 @@ def install_check(options):
if options.conf_ntp and not options.force_chrony: if options.conf_ntp and not options.force_chrony:
try: try:
ntpconf.check_timedate_services() timeconf.check_timedate_services()
except ntpconf.NTPConflictingService as e: except timeconf.NTPConflictingService as e:
print("WARNING: chronyd time&date synchronization service will not" print("WARNING: chronyd time&date synchronization service will not"
" be configured as") " be configured as")
print("conflicting service ({}) is enabled".format( print("conflicting service ({}) is enabled".format(
@ -1998,10 +1998,10 @@ def install_check(options):
print("Use --force-chrony option to disable it and force " print("Use --force-chrony option to disable it and force "
"use of chronyd") "use of chronyd")
print("") print("")
# TODO decide what to do if there is conflicting service
# configuration of chrony is disabled in this case # configuration of chrony is disabled in this case
options.conf_ntp = False options.conf_ntp = False
except ntpconf.NTPConfigurationError: except timeconf.NTPConfigurationError:
pass pass
if options.unattended and ( if options.unattended and (
@ -2345,18 +2345,21 @@ def update_ipa_nssdb():
(nickname, sys_db.secdir, e)) (nickname, sys_db.secdir, e))
def sync_time(options, fstore, statestore): def sync_time(options, fstore, statestore, force):
# We assume that NTP servers are discoverable through SRV records """
# in the DNS. Will disable any other time synchronization service if there is
# If that fails, we try to sync directly with IPA server, --force-chrony option set, and configure chrony with given ntp(chrony)
# assuming it runs NTP 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 # disable other time&date services first
if options.force_chrony: if force:
ntpconf.force_chrony(statestore) timeconf.force_chrony(statestore)
print("Synchronizing time") print("Synchronizing time")
print(" [1/1]: Configuring chrony client")
logger.info('Synchronizing time with KDC...') logger.info('Synchronizing time with KDC...')
if not options.ntp_servers: if not options.ntp_servers:
@ -2367,37 +2370,37 @@ def sync_time(options, fstore, statestore):
ntp_servers = options.ntp_servers ntp_servers = options.ntp_servers
if ntp_servers: if ntp_servers:
synced_time = ntpconf.configure_chrony(ntp_servers, options.ntp_pool, if timeconf.configure_chrony(ntp_servers, options.ntp_pool,
fstore, statestore) 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: else:
synced_time = False print("Warning: chrony not configured, using default configuration.")
logger.warning("No SRV records of NTP servers found nor NTP server " logger.warning("No SRV records of NTP servers found nor NTP server "
"address was privided. Skipping chrony configuration") "address was provided. Skipping chrony configuration, "
"default configuration will be used")
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): def restore_time_sync(statestore, fstore):
chrony_configured = statestore.has_state('ntp') if statestore.has_state('chrony'):
if chrony_configured: chrony_enabled = statestore.restore_state('chrony', 'enabled')
chrony_enabled = statestore.restore_state('ntp', 'enabled')
restored = False restored = False
try: try:
# Restore might fail due to file missing in backup # Restore might fail due to missing file(s) in backup.
# the reason for it might be that freeipa-client was updated # One example is if the client was updated from a previous version
# to this version but not unenrolled/enrolled again # not configured with chrony. In such a cast it is OK to fail.
# In such case it is OK to fail
restored = fstore.restore_file(paths.CHRONY_CONF) restored = fstore.restore_file(paths.CHRONY_CONF)
except Exception: except ValueError: # this will not handle possivble IOError
pass logger.debug("Configuration file %s was not restored.",
paths.CHRONY_CONF)
if not chrony_enabled: if not chrony_enabled:
services.knownservices.chronyd.stop() services.knownservices.chronyd.stop()
@ -2406,7 +2409,7 @@ def restore_time_sync(statestore, fstore):
services.knownservices.chronyd.restart() services.knownservices.chronyd.restart()
try: try:
ntpconf.restore_forced_chronyd(statestore) timeconf.restore_forced_timeservices(statestore)
except CalledProcessError as e: except CalledProcessError as e:
logger.error('Failed to restore time synchronization service: %s', e) logger.error('Failed to restore time synchronization service: %s', e)
@ -2458,7 +2461,7 @@ def _install(options):
if options.conf_ntp: if options.conf_ntp:
# Attempt to sync time with NTP server (chrony). # 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: elif options.on_master:
# If we're on master skipping the time sync here because it was done # If we're on master skipping the time sync here because it was done
# in ipa-server-install # in ipa-server-install
@ -3472,6 +3475,7 @@ class ClientInstallInterface(hostname_.HostNameInstallInterface,
force_ntpd = knob( force_ntpd = knob(
None, False, None, False,
deprecated=True,
description="Stop and disable any time&date synchronization services " description="Stop and disable any time&date synchronization services "
"besides ntpd.\n" "besides ntpd.\n"
"This option has been obsoleted by --force-chrony", "This option has been obsoleted by --force-chrony",

View File

@ -79,10 +79,10 @@ def configure_chrony(ntp_servers, ntp_pool=None,
try: try:
aug.save() aug.save()
except Exception as e: except IOError as e:
logger.error("Augeas failed to configure file %s", chrony_conf) 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) logger.error("Configuration failed with: %s", e)
finally: finally:
aug.close() aug.close()
@ -101,20 +101,19 @@ def configure_chrony(ntp_servers, ntp_pool=None,
# 3 attempts means if first immidiate attempt fails # 3 attempts means if first immidiate attempt fails
# there is 10s delay between next # there is 10s delay between next
cmd = [paths.CHRONYC, 'waitsync', str(sync_attempt_count)] args = [paths.CHRONYC, 'waitsync', str(sync_attempt_count)]
if debug: if debug:
cmd.append('-d') args.append('-d')
try: try:
logger.info('Attempting to sync time using chronyd.') logger.info('Attempting to sync time using chronyd.')
ipautil.run(cmd) ipautil.run(args)
logger.info('Time is in sync.') logger.info('Time synchronization was successful.')
return True return True
except ipautil.CalledProcessError as e: except ipautil.CalledProcessError:
if e.returncode is 1: logger.warning('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.')
logger.warning('Configuration of chrony was changed by installer.')
return False return False
@ -167,13 +166,13 @@ def force_chrony(statestore):
instance.disable() 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 Restore from --force-chronyd installation and enable/start service that
were disabled/stopped during installation were disabled/stopped during installation
""" """
for service in services.timedate_services: for service in services.timedate_services:
if service == 'chronyd': if service == skip_service:
continue continue
if statestore.has_state(service): if statestore.has_state(service):
instance = services.service(service, api) instance = services.service(service, api)

View File

@ -230,7 +230,6 @@ class BasePathNamespace(object):
NAMED_PKCS11 = "/usr/sbin/named-pkcs11" NAMED_PKCS11 = "/usr/sbin/named-pkcs11"
CHRONYC = "/usr/bin/chronyc" CHRONYC = "/usr/bin/chronyc"
CHRONYD = "/usr/sbin/chronyd" CHRONYD = "/usr/sbin/chronyd"
CHRONY_HELPER = "/usr/libexec/chrony-helper"
PKIDESTROY = "/usr/sbin/pkidestroy" PKIDESTROY = "/usr/sbin/pkidestroy"
PKISPAWN = "/usr/sbin/pkispawn" PKISPAWN = "/usr/sbin/pkispawn"
PKI = "/usr/bin/pki" PKI = "/usr/bin/pki"

View File

@ -162,7 +162,7 @@ class Backup(admintool.AdminTool):
paths.IPA_CA_CRT, paths.IPA_CA_CRT,
paths.IPA_DEFAULT_CONF, paths.IPA_DEFAULT_CONF,
paths.DS_KEYTAB, paths.DS_KEYTAB,
paths.NTP_CONF, paths.CHRONY_CONF,
paths.SMB_CONF, paths.SMB_CONF,
paths.SAMBA_KEYTAB, paths.SAMBA_KEYTAB,
paths.DOGTAG_ADMIN_P12, paths.DOGTAG_ADMIN_P12,

View File

@ -31,7 +31,7 @@ from ipalib.util import (
validate_domain_name, validate_domain_name,
no_matching_interface_for_ip_address_warning, no_matching_interface_for_ip_address_warning,
) )
import ipaclient.install.ntpconf import ipaclient.install.timeconf
from ipaserver.install import ( from ipaserver.install import (
adtrust, bindinstance, ca, dns, dsinstance, adtrust, bindinstance, ca, dns, dsinstance,
httpinstance, installutils, kra, krbinstance, httpinstance, installutils, kra, krbinstance,
@ -413,13 +413,13 @@ def install_check(installer):
if not options.no_ntp: if not options.no_ntp:
try: try:
ipaclient.install.ntpconf.check_timedate_services() ipaclient.install.timeconf.check_timedate_services()
except ipaclient.install.ntpconf.NTPConflictingService as e: except ipaclient.install.timeconf.NTPConflictingService as e:
print("WARNING: conflicting time&date synchronization service '%s'" print("WARNING: conflicting time&date synchronization service '{}'"
" will be disabled" % e.conflicting_service) " will be disabled".format(e.conflicting_service))
print("in favor of chronyd") print("in favor of chronyd")
print("") print("")
except ipaclient.install.ntpconf.NTPConfigurationError: except ipaclient.install.timeconf.NTPConfigurationError:
pass pass
if not options.setup_dns and installer.interactive: 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 # chrony will be handled here in uninstall() method as well by invoking
# the ipa-server-install --uninstall # the ipa-server-install --uninstall
if not options.no_ntp: 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: if options.dirsrv_cert_files:
ds = dsinstance.DsInstance(fstore=fstore, ds = dsinstance.DsInstance(fstore=fstore,
@ -1119,7 +1120,7 @@ def uninstall(installer):
sstore._load() 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) # Clean up group_exists (unused since IPA 2.2, not being set since 4.1)
sstore.restore_state("install", "group_exists") sstore.restore_state("install", "group_exists")

View File

@ -23,7 +23,7 @@ from pkg_resources import parse_version
import six import six
from ipaclient.install.ipachangeconf import IPAChangeConf from ipaclient.install.ipachangeconf import IPAChangeConf
import ipaclient.install.ntpconf import ipaclient.install.timeconf
from ipalib.install import certstore, sysrestore from ipalib.install import certstore, sysrestore
from ipalib.install.kinit import kinit_keytab from ipalib.install.kinit import kinit_keytab
from ipapython import ipaldap, ipautil from ipapython import ipaldap, ipautil
@ -581,12 +581,12 @@ def common_check(no_ntp):
if not no_ntp: if not no_ntp:
try: try:
ipaclient.install.ntpconf.check_timedate_services() ipaclient.install.timeconf.check_timedate_services()
except ipaclient.install.ntpconf.NTPConflictingService as e: except ipaclient.install.timeconf.NTPConflictingService as e:
print("WARNING: conflicting time&date synchronization service " print("WARNING: conflicting time&date synchronization service "
"'{svc}' will\nbe disabled in favor of chronyd\n" "'{svc}' will\nbe disabled in favor of chronyd\n"
.format(svc=e.conflicting_service)) .format(svc=e.conflicting_service))
except ipaclient.install.ntpconf.NTPConfigurationError: except ipaclient.install.timeconf.NTPConfigurationError:
pass pass
@ -1391,7 +1391,7 @@ def install(installer):
if not promote and not options.no_ntp: if not promote and not options.no_ntp:
# in DL1, chrony is already installed # in DL1, chrony is already installed
ipaclient.install.ntpconf.force_chrony(sstore) ipaclient.install.timeconf.force_chrony(sstore)
try: try:
if promote: if promote:

View File

@ -20,6 +20,7 @@ from ipalib.install import certmonger, sysrestore
import SSSDConfig import SSSDConfig
import ipalib.util import ipalib.util
import ipalib.errors import ipalib.errors
from ipaclient.install import timeconf
from ipaclient.install.client import sssd_enable_service from ipaclient.install.client import sssd_enable_service
from ipaplatform import services from ipaplatform import services
from ipaplatform.tasks import tasks from ipaplatform.tasks import tasks
@ -1593,6 +1594,41 @@ def enable_certauth(krb):
aug.close() 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(): def upgrade_configuration():
""" """
Execute configuration upgrade of the IPA services Execute configuration upgrade of the IPA services
@ -1613,6 +1649,9 @@ def upgrade_configuration():
if not ds_running: if not ds_running:
ds.start(ds_serverid) ds.start(ds_serverid)
if not sysupgrade.get_upgrade_state('ntpd', 'ntpd_cleaned'):
ntpd_cleanup(fqdn, fstore)
check_certs() check_certs()
auto_redirect = find_autoredirect(fqdn) auto_redirect = find_autoredirect(fqdn)