Files
freeipa/ipaclient/install/timeconf.py
T

205 lines
6.8 KiB
Python
Raw Normal View History

# Authors: Karl MacMillan <kmacmillan@redhat.com>
#
# Copyright (C) 2007 Red Hat
# see file 'COPYING' for use and warranty information
#
2010-12-09 13:59:11 +01:00
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
2010-12-09 13:59:11 +01:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
2018-04-05 09:21:16 +02:00
from __future__ import absolute_import
2017-05-24 14:35:07 +00:00
import logging
import os
import shutil
2018-02-22 12:12:24 +01:00
from augeas import Augeas
from ipalib import api
from ipapython import ipautil
from ipaplatform.tasks import tasks
from ipaplatform import services
from ipaplatform.paths import paths
2017-05-24 14:35:07 +00:00
logger = logging.getLogger(__name__)
2018-02-22 12:12:24 +01:00
def __backup_config(path, fstore=None):
if fstore:
fstore.backup_file(path)
else:
shutil.copy(path, "%s.ipasave" % (path))
2008-03-31 17:33:55 -04:00
def sync_chrony():
"""
This method enables chronyd service on boot and restarts it to reload
chrony configuration file /etc/chrony.conf
Then it tries to synchronize time with chrony's new or defaut configuration
"""
# Set the chronyd to start on boot
services.knownservices.chronyd.enable()
# Restart chronyd
services.knownservices.chronyd.restart()
sync_attempt_count = 3
# chrony attempt count to sync with configiured servers
# each next attempt is tried after 10seconds of timeot
# 3 attempts means: if first immidiate attempt fails
# there is 10s delay between next attempts
args = [paths.CHRONYC, 'waitsync', str(sync_attempt_count), '-d']
try:
logger.info('Attempting to sync time with chronyc.')
ipautil.run(args)
logger.info('Time synchronization was successful.')
return True
except ipautil.CalledProcessError:
logger.warning('Process chronyc waitsync failed to sync 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.")
return False
2018-03-12 13:36:12 +01:00
def configure_chrony(ntp_servers, ntp_pool=None,
fstore=None, sysstore=None, debug=False):
"""
This method only configures chrony client with ntp_servers or ntp_pool
"""
module = "chrony"
2018-02-22 12:12:24 +01:00
if sysstore:
sysstore.backup_state(module, "enabled",
services.knownservices.chronyd.is_enabled())
2008-03-31 17:33:55 -04:00
2018-02-22 12:12:24 +01:00
aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD,
loadpath=paths.USR_SHARE_IPA_DIR)
2008-03-31 17:33:55 -04:00
2018-02-22 12:12:24 +01:00
try:
logger.debug("Configuring chrony")
chrony_conf = os.path.abspath(paths.CHRONY_CONF)
aug.transform(module, chrony_conf) # loads chrony lens file
2018-02-22 12:12:24 +01:00
aug.load() # loads augeas tree
# augeas needs to prepend path with '/files'
path = '/files{path}'.format(path=chrony_conf)
2008-03-31 17:33:55 -04:00
2018-02-22 12:12:24 +01:00
# remove possible conflicting configuration of servers
aug.remove('{}/server'.format(path))
aug.remove('{}/pool'.format(path))
aug.remove('{}/peer'.format(path))
2018-03-12 13:36:12 +01:00
if ntp_pool:
logger.debug("Setting server pool:")
logger.debug("'%s'", ntp_pool)
aug.set('{}/pool[last()+1]'.format(path), ntp_pool)
aug.set('{}/pool[last()]/iburst'.format(path), None)
if ntp_servers:
logger.debug("Setting time servers:")
for server in ntp_servers:
aug.set('{}/server[last()+1]'.format(path), server)
aug.set('{}/server[last()]/iburst'.format(path), None)
logger.debug("'%s'", server)
2008-03-31 17:33:55 -04:00
2018-02-22 12:12:24 +01:00
# backup oginal conf file
logger.debug("Backing up '%s'", chrony_conf)
__backup_config(chrony_conf, fstore)
2018-02-22 12:12:24 +01:00
logger.debug("Writing configuration to '%s'", chrony_conf)
aug.save()
2008-03-31 17:33:55 -04:00
logger.info('Configuration of chrony was changed by installer.')
configured = True
2008-03-31 17:33:55 -04:00
except IOError:
logger.error("Augeas failed to configure file %s", chrony_conf)
configured = False
except RuntimeError as e:
2018-02-22 12:12:24 +01:00
logger.error("Configuration failed with: %s", e)
configured = False
2018-02-22 12:12:24 +01:00
finally:
aug.close()
2018-02-22 12:12:24 +01:00
tasks.restore_context(chrony_conf)
return configured
class NTPConfigurationError(Exception):
pass
2018-02-22 12:12:24 +01:00
class NTPConflictingService(NTPConfigurationError):
def __init__(self, message='', conflicting_service=None):
super(NTPConflictingService, self).__init__(self, message)
self.conflicting_service = conflicting_service
2018-02-22 12:12:24 +01:00
def check_timedate_services():
"""
System may contain conflicting services used for time&date synchronization.
2018-02-22 12:12:24 +01:00
As IPA server/client supports only chronyd, make sure that other services
are not enabled to prevent conflicts.
"""
for service in services.timedate_services:
2018-02-22 12:12:24 +01:00
if service == 'chronyd':
continue
# Make sure that the service is not enabled
instance = services.service(service, api)
2014-06-03 16:09:16 +02:00
if instance.is_enabled() or instance.is_running():
2018-02-22 12:12:24 +01:00
raise NTPConflictingService(
conflicting_service=instance.service_name)
2018-02-22 12:12:24 +01:00
def force_chrony(statestore):
"""
2018-02-22 12:12:24 +01:00
Force chronyd configuration and disable and stop any other conflicting
time&date service
"""
for service in services.timedate_services:
2018-02-22 12:12:24 +01:00
if service == 'chronyd':
continue
instance = services.service(service, api)
2014-06-03 16:09:16 +02:00
enabled = instance.is_enabled()
running = instance.is_running()
if enabled or running:
2014-06-03 16:09:16 +02:00
statestore.backup_state(instance.service_name, 'enabled', enabled)
statestore.backup_state(instance.service_name, 'running', running)
if running:
2014-06-03 16:09:16 +02:00
instance.stop()
if enabled:
2014-06-03 16:09:16 +02:00
instance.disable()
2018-02-22 12:12:24 +01:00
def restore_forced_timeservices(statestore, skip_service='chronyd'):
"""
2018-03-26 15:54:13 +02:00
Restore from installation and enable/start service that
2018-02-22 12:12:24 +01:00
were disabled/stopped during installation
"""
for service in services.timedate_services:
if service == skip_service:
continue
if statestore.has_state(service):
instance = services.service(service, api)
2018-02-22 12:12:24 +01:00
enabled = statestore.restore_state(instance.service_name,
'enabled')
running = statestore.restore_state(instance.service_name,
'running')
if enabled:
2014-06-03 16:09:16 +02:00
instance.enable()
if running:
2014-06-03 16:09:16 +02:00
instance.start()