mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 16:10:02 -06:00
b5bdd07bc5
Add absolute_import from __future__ so that pylint does not fail and to achieve python3 behavior in python2. Reviewed-By: Christian Heimes <cheimes@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
205 lines
6.8 KiB
Python
205 lines
6.8 KiB
Python
# Authors: Karl MacMillan <kmacmillan@redhat.com>
|
|
#
|
|
# Copyright (C) 2007 Red Hat
|
|
# see file 'COPYING' for use and warranty information
|
|
#
|
|
# 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
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
from __future__ import absolute_import
|
|
|
|
import logging
|
|
import os
|
|
import shutil
|
|
|
|
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
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def __backup_config(path, fstore=None):
|
|
if fstore:
|
|
fstore.backup_file(path)
|
|
else:
|
|
shutil.copy(path, "%s.ipasave" % (path))
|
|
|
|
|
|
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
|
|
|
|
|
|
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"
|
|
if sysstore:
|
|
sysstore.backup_state(module, "enabled",
|
|
services.knownservices.chronyd.is_enabled())
|
|
|
|
aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD,
|
|
loadpath=paths.USR_SHARE_IPA_DIR)
|
|
|
|
try:
|
|
logger.debug("Configuring chrony")
|
|
chrony_conf = os.path.abspath(paths.CHRONY_CONF)
|
|
aug.transform(module, chrony_conf) # loads chrony lens file
|
|
aug.load() # loads augeas tree
|
|
# augeas needs to prepend path with '/files'
|
|
path = '/files{path}'.format(path=chrony_conf)
|
|
|
|
# remove possible conflicting configuration of servers
|
|
aug.remove('{}/server'.format(path))
|
|
aug.remove('{}/pool'.format(path))
|
|
aug.remove('{}/peer'.format(path))
|
|
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)
|
|
|
|
# backup oginal conf file
|
|
logger.debug("Backing up '%s'", chrony_conf)
|
|
__backup_config(chrony_conf, fstore)
|
|
|
|
logger.debug("Writing configuration to '%s'", chrony_conf)
|
|
aug.save()
|
|
|
|
logger.info('Configuration of chrony was changed by installer.')
|
|
configured = True
|
|
|
|
except IOError:
|
|
logger.error("Augeas failed to configure file %s", chrony_conf)
|
|
configured = False
|
|
except RuntimeError as e:
|
|
logger.error("Configuration failed with: %s", e)
|
|
configured = False
|
|
finally:
|
|
aug.close()
|
|
|
|
tasks.restore_context(chrony_conf)
|
|
return configured
|
|
|
|
|
|
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 chronyd, make sure that other services
|
|
are not enabled to prevent conflicts.
|
|
"""
|
|
for service in services.timedate_services:
|
|
if service == 'chronyd':
|
|
continue
|
|
# Make sure that the service is not enabled
|
|
instance = services.service(service, api)
|
|
if instance.is_enabled() or instance.is_running():
|
|
raise NTPConflictingService(
|
|
conflicting_service=instance.service_name)
|
|
|
|
|
|
def force_chrony(statestore):
|
|
"""
|
|
Force chronyd configuration and disable and stop any other conflicting
|
|
time&date service
|
|
"""
|
|
for service in services.timedate_services:
|
|
if service == 'chronyd':
|
|
continue
|
|
instance = services.service(service, api)
|
|
enabled = instance.is_enabled()
|
|
running = instance.is_running()
|
|
|
|
if enabled or running:
|
|
statestore.backup_state(instance.service_name, 'enabled', enabled)
|
|
statestore.backup_state(instance.service_name, 'running', running)
|
|
|
|
if running:
|
|
instance.stop()
|
|
|
|
if enabled:
|
|
instance.disable()
|
|
|
|
|
|
def restore_forced_timeservices(statestore, skip_service='chronyd'):
|
|
"""
|
|
Restore from installation and enable/start service that
|
|
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)
|
|
enabled = statestore.restore_state(instance.service_name,
|
|
'enabled')
|
|
running = statestore.restore_state(instance.service_name,
|
|
'running')
|
|
if enabled:
|
|
instance.enable()
|
|
if running:
|
|
instance.start()
|