FreeIPA server is time synchronization client only

This will change behaviour that FreeIPA server will be no more
ntpd server and time service is no longer part of FreeIPA topology.

As dependency for ntpd was completely removed, and there is only
dependency for chrony, FreeIPA will configure every host to
became chronyd service's clients.

FreeIPA have not supported --ntp-server option now it must to
support client configuration of chrony.

Configuration of chrony is moved to client-install therefore
NTP related options are now passed to the ipa-client-install
script method sync_time which now handles configuration of chrony.

Server installation has to configure chrony before handling
certificates so there is call to configure chrony outside of
using server's statestore and filestore.

Removed behavior that there is always --no-ntp option set.

Resolves: https://pagure.io/freeipa/issue/7024
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Tibor Dudlák 2018-03-05 16:42:39 +01:00 committed by Rob Crittenden
parent ca9c4d70a0
commit fb28dfff93
4 changed files with 93 additions and 66 deletions

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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()