cloud-init/0001-Support-chrony-configuration-lp-1731619.patch
Robert Schweikert c083c6be27 - Update to version 18.1 (bsc#1092637, bsc#1084509)
+ Forward port cloud-init-python2-sigpipe.patch
  + Forward port cloud-init-no-python-linux-dist.patch
  + Add cloud-init-no-trace-empt-sect.patch
  + Hetzner: Exit early if dmi system-manufacturer is not Hetzner.
  + Add missing dependency on isc-dhcp-client to trunk ubuntu packaging.
  + (LP: #1759307)
  + FreeBSD: resizefs module now able to handle zfs/zpool.
  + [Dominic Schlegel] (LP: #1721243)
  + cc_puppet: Revert regression of puppet creating ssl and ssl_cert dirs
  + Enable IBMCloud datasource in settings.py.
  + IBMCloud: Initial IBM Cloud datasource.
  + tests: remove jsonschema from xenial tox environment.
  + tests: Fix newly added schema unit tests to skip if no jsonschema.
  + ec2: Adjust ec2 datasource after exception_cb change.
  + Reduce AzurePreprovisioning HTTP timeouts.
  + [Douglas Jordan] (LP: #1752977)
  + Revert the logic of exception_cb in read_url.
  + [Kurt Garloff] (LP: #1702160, #1298921)
  + ubuntu-advantage: Add new config module to support
  + ubuntu-advantage-tools
  + Handle global dns entries in netplan (LP: #1750884)
  + Identify OpenTelekomCloud Xen as OpenStack DS.
  + [Kurt Garloff] (LP: #1756471)
  + datasources: fix DataSource subclass get_hostname method signature
  + (LP: #1757176)
  + OpenNebula: Update network to return v2 config rather than ENI.
  + [Akihiko Ota]
  + Add Hetzner Cloud DataSource
  + net: recognize iscsi root cases without ip= on kernel command line.

OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/cloud-init?expand=0&rev=110
2018-05-11 20:14:40 +00:00

273 lines
11 KiB
Diff

From 23f976be51ba9ad6e1e173f23c7220144beb942a Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
Date: Tue, 14 Nov 2017 18:24:17 -0500
Subject: [PATCH 1/3] - Support chrony configuration (lp#1731619) + Add a
template for chrony configuration + Add new set_timesync_client to distros
base class - Set the timesync client provided in the config by the user
with system_info: ntp_client - If no user config set the timesync
client to one of the supported clients if the executable is installed
- Fall back to the distribution default + Handle the new settings in
cc_ntp while retaining current behavior as the fallback until all distro
implementations have switched to the new implementation + Use new way
of ntp client configuration for openSUSE and SLES + Unit tests
---
cloudinit/config/cc_ntp.py | 59 +++++++++----
cloudinit/distros/__init__.py | 40 +++++++++
cloudinit/distros/arch.py | 4 +
cloudinit/distros/debian.py | 4 +
cloudinit/distros/freebsd.py | 4 +
cloudinit/distros/gentoo.py | 4 +
cloudinit/distros/opensuse.py | 41 +++++++++
cloudinit/distros/rhel.py | 4 +
templates/chrony.conf.tmpl | 25 ++++++
tests/unittests/test_distros/test_generic.py | 101 +++++++++++++++++++++--
tests/unittests/test_distros/test_opensuse.py | 44 +++++++++-
tests/unittests/test_distros/test_sles.py | 30 ++++++-
tests/unittests/test_handler/test_handler_ntp.py | 80 ++++++++++++++----
13 files changed, 400 insertions(+), 40 deletions(-)
create mode 100644 templates/chrony.conf.tmpl
--- cloudinit/config/cc_ntp.py.orig
+++ cloudinit/config/cc_ntp.py
@@ -20,8 +20,9 @@ from textwrap import dedent
LOG = logging.getLogger(__name__)
frequency = PER_INSTANCE
-NTP_CONF = '/etc/ntp.conf'
-TIMESYNCD_CONF = '/etc/systemd/timesyncd.conf.d/cloud-init.conf'
+CHRONY_CONF_FILE = '/etc/chrony.conf'
+NTP_CONF_FILE = '/etc/ntp.conf'
+TIMESYNCD_CONF_FILE = '/etc/systemd/timesyncd.conf.d/cloud-init.conf'
NR_POOL_SERVERS = 4
distros = ['centos', 'debian', 'fedora', 'opensuse', 'sles', 'ubuntu']
@@ -49,6 +50,7 @@ schema = {
'examples': [
dedent("""\
ntp:
+ enabled: true
pools: [0.int.pool.ntp.org, 1.int.pool.ntp.org, ntp.myorg.org]
servers:
- ntp.server.local
@@ -60,6 +62,9 @@ schema = {
'ntp': {
'type': ['object', 'null'],
'properties': {
+ 'enabled': {
+ "type": "boolean"
+ },
'pools': {
'type': 'array',
'items': {
@@ -110,26 +115,48 @@ def handle(name, cfg, cloud, log, _args)
"'ntp' key existed in config, but not a dictionary type,"
" is a {_type} instead".format(_type=type_utils.obj_name(ntp_cfg)))
+ if ntp_cfg.get('enabled'):
+ cloud.distro.set_timesync_client()
+ else:
+ # When all distro implementations are switched return here
+ pass
+
validate_cloudconfig_schema(cfg, schema)
- if ntp_installable():
- service_name = 'ntp'
- confpath = NTP_CONF
- template_name = None
- packages = ['ntp']
- check_exe = 'ntpd'
+ if hasattr(cloud.distro, 'timesync_client'):
+ client_name = cloud.distro.timesync_client
+ service_name = cloud.distro.timesync_service_name
+ if client_name == 'ntp':
+ confpath = NTP_CONF_FILE
+ template_name = 'ntp.conf.%s' % cloud.distro.name
+ elif client_name == 'systemd-timesyncd':
+ confpath = TIMESYNCD_CONF_FILE
+ template_name = 'timesyncd.conf'
+ elif client_name == 'chrony':
+ confpath = CHRONY_CONF_FILE
+ template_name = 'chrony.conf.%s' % cloud.distro.name
else:
- service_name = 'systemd-timesyncd'
- confpath = TIMESYNCD_CONF
- template_name = 'timesyncd.conf'
- packages = []
- check_exe = '/lib/systemd/systemd-timesyncd'
+ if ntp_installable():
+ service_name = 'ntp'
+ confpath = NTP_CONF_FILE
+ template_name = None
+ packages = ['ntp']
+ check_exe = 'ntpd'
+ else:
+ service_name = 'systemd-timesyncd'
+ confpath = TIMESYNCD_CONF_FILE
+ template_name = 'timesyncd.conf'
+ packages = []
+ check_exe = '/lib/systemd/systemd-timesyncd'
- rename_ntp_conf()
+ rename_ntp_conf(confpath)
# ensure when ntp is installed it has a configuration file
# to use instead of starting up with packaged defaults
write_ntp_config_template(ntp_cfg, cloud, confpath, template=template_name)
- install_ntp(cloud.distro.install_packages, packages=packages,
- check_exe=check_exe)
+ if not hasattr(cloud.distro, 'timesync_client'):
+ # Updated implementation installs a package is missing in
+ # distro._set_default_timesync_client
+ install_ntp(cloud.distro.install_packages, packages=packages,
+ check_exe=check_exe)
try:
reload_ntp(service_name, systemd=cloud.distro.uses_systemd())
@@ -167,7 +194,7 @@ def install_ntp(install_func, packages=N
def rename_ntp_conf(config=None):
"""Rename any existing ntp.conf file"""
if config is None: # For testing
- config = NTP_CONF
+ config = NTP_CONF_FILE
if os.path.exists(config):
util.rename(config, config + ".dist")
--- cloudinit/distros/__init__.py.orig
+++ cloudinit/distros/__init__.py
@@ -61,6 +61,9 @@ class Distro(object):
init_cmd = ['service'] # systemctl, service etc
renderer_configs = {}
+ __timesync_client_map = {}
+ __ntp_client_execs = []
+
def __init__(self, name, cfg, paths):
self._paths = paths
self._cfg = cfg
@@ -90,6 +93,43 @@ class Distro(object):
renderer.render_network_config(network_config=network_config)
return []
+ def set_timesync_client(self):
+ system_info = self._cfg.get('system_info')
+ if system_info and isinstance(system_info, (dict)):
+ ntp_client = system_info.get('ntp_client')
+ if ntp_client and ntp_client in self.__timesync_client_map:
+ self.timesync_client, self.timesync_service_name = \
+ self.__timesync_client_map.get(ntp_client)
+ LOG.debug('Using "%s" for timesync client per configuration',
+ ntp_client)
+ return
+
+ found = False
+ for ntp_client in self.__ntp_client_execs:
+ ntp_exec = util.which(ntp_client)
+ if ntp_exec and not found:
+ found = ntp_client
+ # systemd-timesyncd is part of systemd and thus is probably
+ # always installed, do not consider it as a conflict
+ elif ntp_exec and found and 'systemd-timesyncd' not in ntp_exec:
+ msg = 'Found multiple timesync clients installed. Resolve '
+ msg += 'ambigutity by falling back to distro default'
+ LOG.debug(msg)
+ found = False
+ break
+
+ if found and found in self.__timesync_client_map:
+ self.timesync_client, self.timesync_service_name = \
+ self.__timesync_client_map.get(found)
+ LOG.debug('Using "%s" for timesync based on installed exec',
+ ntp_client)
+ return
+
+ self._set_default_timesync_client()
+
+ def _set_default_timesync_client(self):
+ raise NotImplementedError()
+
def _find_tz_file(self, tz):
tz_file = os.path.join(self.tz_zone_dir, str(tz))
if not os.path.isfile(tz_file):
--- /dev/null
+++ templates/chrony.conf.tmpl
@@ -0,0 +1,24 @@
+## template:jinja
+# cloud-init generated file
+# See chrony.conf(5)
+
+{% if pools %}# pools
+{% endif %}
+{% for pool in pools -%}
+pool {{pool}} iburst
+{% endfor %}
+{%- if servers %}# servers
+{% endif %}
+{% for server in servers -%}
+server {{server}} iburst
+{% endfor %}
+
+# Record the rate at which the the system clock gains/losses time
+driftfile /var/lib/chrony/drift
+
+# Allow the system clock to be stepped in the first three updates
+# if its offset is larger than 1 second.
+makestep 1.0 3
+
+# Enable kernel synchronization of the real-time clock (RTC).
+rtcsync
--- cloudinit/distros/opensuse.py.orig
+++ cloudinit/distros/opensuse.py
@@ -36,6 +36,23 @@ class Distro(distros.Distro):
systemd_locale_conf_fn = '/etc/locale.conf'
tz_local_fn = '/etc/localtime'
+ __timesync_client_map = {
+ # Map the system_info supported values
+ 'chrony': ('chrony', 'chronyd'),
+ 'isc-ntp': ('ntp', 'ntpd'),
+ 'systemd-timesyncd': ('systemd-timesyncd', 'systemd-timesyncd'),
+ # Map the common names if different from system_info
+ 'chronyd': ('chrony', 'chronyd'),
+ 'ntpd': ('ntp', 'ntpd'),
+ '/usr/lib/systemd/systemd-timesyncd':
+ ('systemd-timesyncd', 'systemd-timesyncd')
+ }
+ __ntp_client_execs = [
+ 'chronyd',
+ 'ntpd',
+ '/usr/lib/systemd/systemd-timesyncd'
+ ]
+
def __init__(self, name, cfg, paths):
distros.Distro.__init__(self, name, cfg, paths)
self._runner = helpers.Runners(paths)
@@ -145,6 +162,28 @@ class Distro(distros.Distro):
host_fn = self.hostname_conf_fn
return (host_fn, self._read_hostname(host_fn))
+ def _set_default_timesync_client(self):
+ """The default timesync client is dependent on the distribution."""
+ # When we get here the user has configured ntp to be enabled but
+ # no client is installed
+ distro_info = util.get_linux_distro()
+ name = distro_info[0]
+ major_ver = int(distro_info[1].split('.')[0])
+
+ # This is horribly complicated because of a case of
+ # "we do not care if versions should be increasing syndrome"
+ if (
+ (major_ver >= 15 and 'openSUSE' not in name) or
+ (major_ver >= 15 and 'openSUSE' in name and major_ver != 42)
+ ):
+ self.timesync_client = 'chrony'
+ self.timesync_service_name = 'chronyd'
+ self.install_packages(['chrony'])
+ else:
+ self.timesync_client = 'ntp'
+ self.timesync_service_name = 'ntpd'
+ self.install_packages(['ntp'])
+
def _write_hostname(self, hostname, out_fn):
if self.uses_systemd() and out_fn.endswith('/previous-hostname'):
util.write_file(out_fn, hostname)