Robert Schweikert
c083c6be27
+ 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
273 lines
11 KiB
Diff
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)
|