diff --git a/0001-Fix-the-service-order-for-SUSE-distributions.patch b/0001-Fix-the-service-order-for-SUSE-distributions.patch new file mode 100644 index 0000000..25144b5 --- /dev/null +++ b/0001-Fix-the-service-order-for-SUSE-distributions.patch @@ -0,0 +1,28 @@ +From 1f7950f72dc5f3603118c0f91dca3fb7145f0801 Mon Sep 17 00:00:00 2001 +From: Robert Schweikert +Date: Wed, 24 Oct 2018 09:50:11 -0400 +Subject: [PATCH] - Fix the service order for SUSE distributions + Network + configuration file gets written when cloud-init.service runs. Therefore + this needs to run prior to the network tools (wicked) + +--- + systemd/cloud-init.service.tmpl | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/systemd/cloud-init.service.tmpl b/systemd/cloud-init.service.tmpl +index b92e8abc..5cb00371 100644 +--- a/systemd/cloud-init.service.tmpl ++++ b/systemd/cloud-init.service.tmpl +@@ -14,8 +14,7 @@ After=networking.service + After=network.service + {% endif %} + {% if variant in ["suse"] %} +-Requires=wicked.service +-After=wicked.service ++Before=wicked.service + # setting hostname via hostnamectl depends on dbus, which otherwise + # would not be guaranteed at this point. + After=dbus.service +-- +2.13.7 + diff --git a/0001-Follow-the-ever-bouncing-ball-for-openSUSE-distribut.patch b/0001-Follow-the-ever-bouncing-ball-for-openSUSE-distribut.patch new file mode 100644 index 0000000..74e5835 --- /dev/null +++ b/0001-Follow-the-ever-bouncing-ball-for-openSUSE-distribut.patch @@ -0,0 +1,40 @@ +From eb504025c76909175ab2d00c25232b89faf01ab4 Mon Sep 17 00:00:00 2001 +From: Robert Schweikert +Date: Sun, 21 Oct 2018 08:28:21 -0400 +Subject: [PATCH 1/2] - Follow the ever bouncing ball for openSUSE distribution + identification + openSUSE changed from identifying itself as "opensuse" in + os-release to "opensuse-tumbleweed" and "opensuse-leap". This breaks + template expansion + +--- + cloudinit/util.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/cloudinit/util.py b/cloudinit/util.py +index c67d6be6..7800f7bc 100644 +--- a/cloudinit/util.py ++++ b/cloudinit/util.py +@@ -615,8 +615,8 @@ def get_linux_distro(): + distro_name = os_release.get('ID', '') + distro_version = os_release.get('VERSION_ID', '') + if 'sles' in distro_name or 'suse' in distro_name: +- # RELEASE_BLOCKER: We will drop this sles ivergent behavior in +- # before 18.4 so that get_linux_distro returns a named tuple ++ # RELEASE_BLOCKER: We will drop this sles divergent behavior in ++ # the future so that get_linux_distro returns a named tuple + # which will include both version codename and architecture + # on all distributions. + flavor = platform.machine() +@@ -668,7 +668,8 @@ def system_info(): + var = 'ubuntu' + elif linux_dist == 'redhat': + var = 'rhel' +- elif linux_dist in ('opensuse', 'sles'): ++ elif linux_dist in ( ++ 'opensuse', 'opensuse-tumbleweed', 'opensuse-leap', 'sles'): + var = 'suse' + else: + var = 'linux' +-- +2.13.7 + diff --git a/0001-Support-chrony-configuration-lp-1731619.patch b/0001-Support-chrony-configuration-lp-1731619.patch deleted file mode 100644 index ab9fcfd..0000000 --- a/0001-Support-chrony-configuration-lp-1731619.patch +++ /dev/null @@ -1,272 +0,0 @@ -From 23f976be51ba9ad6e1e173f23c7220144beb942a Mon Sep 17 00:00:00 2001 -From: Robert Schweikert -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) diff --git a/0001-switch-to-using-iproute2-tools.patch b/0001-switch-to-using-iproute2-tools.patch deleted file mode 100644 index caefaf6..0000000 --- a/0001-switch-to-using-iproute2-tools.patch +++ /dev/null @@ -1,682 +0,0 @@ -From 48c4dcd464d8c6daccf09b3dccc664ad347b34ce Mon Sep 17 00:00:00 2001 -From: Robert Schweikert -Date: Mon, 18 Dec 2017 13:34:21 -0500 -Subject: [PATCH] - switch to using iproute2 tools + ifconfig, netstat and - other tools are being deprecated, switch to using tools that are part of - iproute2 for implementations that support these tools - ---- - cloudinit/config/cc_disable_ec2_metadata.py | 14 +- - .../config/tests/test_disable_ec2_metadata.py | 72 +++++ - cloudinit/netinfo.py | 302 +++++++++++++++------ - cloudinit/tests/test_netinfo.py | 174 +++++++++++- - 4 files changed, 474 insertions(+), 88 deletions(-) - create mode 100644 cloudinit/config/tests/test_disable_ec2_metadata.py - -diff --git a/cloudinit/config/cc_disable_ec2_metadata.py b/cloudinit/config/cc_disable_ec2_metadata.py -index c56319b5..8a166ddf 100644 ---- a/cloudinit/config/cc_disable_ec2_metadata.py -+++ b/cloudinit/config/cc_disable_ec2_metadata.py -@@ -32,13 +32,23 @@ from cloudinit.settings import PER_ALWAYS - - frequency = PER_ALWAYS - --REJECT_CMD = ['route', 'add', '-host', '169.254.169.254', 'reject'] -+REJECT_CMD_IF = ['route', 'add', '-host', '169.254.169.254', 'reject'] -+REJECT_CMD_IP = ['ip', 'route', 'add', 'prohibit', '169.254.169.254'] - - - def handle(name, cfg, _cloud, log, _args): - disabled = util.get_cfg_option_bool(cfg, "disable_ec2_metadata", False) - if disabled: -- util.subp(REJECT_CMD, capture=False) -+ reject_cmd = None -+ if util.which('ifconfig'): -+ reject_cmd = REJECT_CMD_IF -+ elif util.which('ip'): -+ reject_cmd = REJECT_CMD_IP -+ else: -+ log.error(('Neither "route" nor "ip" command found, unable to ' -+ 'manipulate routing table')) -+ return -+ util.subp(reject_cmd, capture=False) - else: - log.debug(("Skipping module named %s," - " disabling the ec2 route not enabled"), name) -diff --git a/cloudinit/config/tests/test_disable_ec2_metadata.py b/cloudinit/config/tests/test_disable_ec2_metadata.py -new file mode 100644 -index 00000000..bade814e ---- /dev/null -+++ b/cloudinit/config/tests/test_disable_ec2_metadata.py -@@ -0,0 +1,72 @@ -+# This file is part of cloud-init. See LICENSE file for license information. -+ -+"""Tests cc_disable_ec2_metadata handler""" -+ -+import cloudinit.config.cc_disable_ec2_metadata as ec2_meta -+ -+from cloudinit.tests.helpers import CiTestCase, mock -+ -+import logging -+ -+LOG = logging.getLogger(__name__) -+ -+DISABLE_CFG = {'disable_ec2_metadata': 'true'} -+ -+ -+class TestEC2MetadataRoute(CiTestCase): -+ -+ @mock.patch('cloudinit.config.cc_disable_ec2_metadata.util.which') -+ @mock.patch('cloudinit.config.cc_disable_ec2_metadata.util.subp') -+ def test_disable_ifconfig(self, m_subp, m_which): -+ """Set the route if ifconfig command is available""" -+ m_subp.side_effect = command_check_ifconfig -+ m_which.side_effect = side_effect_use_ifconfig -+ ec2_meta.handle('foo', DISABLE_CFG, None, LOG, None) -+ -+ @mock.patch('cloudinit.config.cc_disable_ec2_metadata.util.which') -+ @mock.patch('cloudinit.config.cc_disable_ec2_metadata.util.subp') -+ def test_disable_ip(self, m_subp, m_which): -+ """Set the route if ip command is available""" -+ m_subp.side_effect = command_check_ip -+ m_which.side_effect = side_effect_use_ip -+ ec2_meta.handle('foo', DISABLE_CFG, None, LOG, None) -+ -+ @mock.patch('cloudinit.config.cc_disable_ec2_metadata.util.which') -+ @mock.patch('cloudinit.config.cc_disable_ec2_metadata.util.subp') -+ def test_disable_no_tool(self, m_subp, m_which): -+ """Set the route if ip command is available""" -+ m_subp.side_effect = command_dont_reach -+ m_which.side_effect = side_effect_has_no_tool -+ ec2_meta.handle('foo', DISABLE_CFG, None, LOG, None) -+ -+ -+def side_effect_use_ifconfig(tool): -+ if tool == 'ifconfig': -+ return True -+ else: -+ return False -+ -+ -+def side_effect_use_ip(tool): -+ if tool == 'ip': -+ return True -+ else: -+ return False -+ -+ -+def side_effect_has_no_tool(tool): -+ return False -+ -+ -+def command_check_ifconfig(cmd, capture): -+ assert(cmd == ['route', 'add', '-host', '169.254.169.254', 'reject']) -+ -+ -+def command_check_ip(cmd, capture): -+ assert(cmd == ['ip', 'route', 'add', 'prohibit', '169.254.169.254']) -+ -+ -+def command_dont_reach(cmd, capture): -+ assert('Test should not have reached this location' == 0) -+ -+# vi: ts=4 expandtab -diff --git a/cloudinit/netinfo.py b/cloudinit/netinfo.py -index 993b26cf..baad3f92 100644 ---- a/cloudinit/netinfo.py -+++ b/cloudinit/netinfo.py -@@ -19,6 +19,117 @@ LOG = logging.getLogger() - - - def netdev_info(empty=""): -+ if util.which('ifconfig'): -+ return _netdev_info_from_ifconfig(empty) -+ elif util.which('ip'): -+ return _netdev_info_from_ip(empty) -+ else: -+ LOG.error(('Neither "ifconfig" nor "ip" command found, unable to ' -+ 'collect network device information')) -+ return {} -+ -+ -+def route_info(): -+ if util.which('netstat'): -+ return _route_info_from_netstat() -+ elif util.which('ip'): -+ return _route_info_from_ip() -+ else: -+ LOG.error(('Neither "netstat" nor "ip" command found, unable to ' -+ 'collect routing information')) -+ return {} -+ -+ -+def getgateway(): -+ try: -+ routes = route_info() -+ except Exception: -+ pass -+ else: -+ for r in routes.get('ipv4', []): -+ if r['flags'].find("G") >= 0: -+ return "%s[%s]" % (r['gateway'], r['iface']) -+ return None -+ -+ -+def netdev_pformat(): -+ lines = [] -+ try: -+ netdev = netdev_info(empty=".") -+ except Exception: -+ lines.append(util.center("Net device info failed", '!', 80)) -+ else: -+ fields = ['Device', 'Up', 'Address', 'Mask', 'Scope', 'Hw-Address'] -+ tbl = SimpleTable(fields) -+ for (dev, d) in sorted(netdev.items()): -+ tbl.add_row([dev, d["up"], d["addr"], d["mask"], ".", d["hwaddr"]]) -+ if d.get('addr6'): -+ tbl.add_row([dev, d["up"], -+ d["addr6"], ".", d.get("scope6"), d["hwaddr"]]) -+ netdev_s = tbl.get_string() -+ max_len = len(max(netdev_s.splitlines(), key=len)) -+ header = util.center("Net device info", "+", max_len) -+ lines.extend([header, netdev_s]) -+ return "\n".join(lines) -+ -+ -+def route_pformat(): -+ lines = [] -+ try: -+ routes = route_info() -+ except Exception as e: -+ lines.append(util.center('Route info failed', '!', 80)) -+ util.logexc(LOG, "Route info failed: %s" % e) -+ else: -+ if routes.get('ipv4'): -+ fields_v4 = ['Route', 'Destination', 'Gateway', -+ 'Genmask', 'Interface', 'Flags'] -+ tbl_v4 = SimpleTable(fields_v4) -+ for (n, r) in enumerate(routes.get('ipv4')): -+ route_id = str(n) -+ tbl_v4.add_row([route_id, r['destination'], -+ r['gateway'], r['genmask'], -+ r['iface'], r['flags']]) -+ route_s = tbl_v4.get_string() -+ max_len = len(max(route_s.splitlines(), key=len)) -+ header = util.center("Route IPv4 info", "+", max_len) -+ lines.extend([header, route_s]) -+ if routes.get('ipv6'): -+ fields_v6 = ['Route', 'Proto', 'Recv-Q', 'Send-Q', -+ 'Local Address', 'Foreign Address', 'State'] -+ tbl_v6 = SimpleTable(fields_v6) -+ for (n, r) in enumerate(routes.get('ipv6')): -+ route_id = str(n) -+ tbl_v6.add_row([route_id, r['proto'], -+ r['recv-q'], r['send-q'], -+ r['local address'], r['foreign address'], -+ r['state']]) -+ route_s = tbl_v6.get_string() -+ max_len = len(max(route_s.splitlines(), key=len)) -+ header = util.center("Route IPv6 info", "+", max_len) -+ lines.extend([header, route_s]) -+ return "\n".join(lines) -+ -+ -+def debug_info(prefix='ci-info: '): -+ lines = [] -+ netdev_lines = netdev_pformat().splitlines() -+ if prefix: -+ for line in netdev_lines: -+ lines.append("%s%s" % (prefix, line)) -+ else: -+ lines.extend(netdev_lines) -+ route_lines = route_pformat().splitlines() -+ if prefix: -+ for line in route_lines: -+ lines.append("%s%s" % (prefix, line)) -+ else: -+ lines.extend(route_lines) -+ return "\n".join(lines) -+ -+ -+def _netdev_info_from_ifconfig(empty=""): -+ """Use legacy ifconfig output""" - fields = ("hwaddr", "addr", "bcast", "mask") - (ifcfg_out, _err) = util.subp(["ifconfig", "-a"], rcs=[0, 1]) - devs = {} -@@ -84,7 +195,54 @@ def netdev_info(empty=""): - return devs - - --def route_info(): -+def _netdev_info_from_ip(empty=""): -+ """Use ip to get network information""" -+ fields = ("hwaddr", "addr", "bcast", "mask") -+ (ipdata_out, _err) = util.subp(["ip", "a"], rcs=[0, 1]) -+ devs = {} -+ this_device = None -+ for line in str(ipdata_out).splitlines(): -+ if len(line) == 0: -+ continue -+ if line[0].isdigit(): -+ prts = line.strip().split(':') -+ this_device = prts[1].strip() -+ devs[this_device] = {} -+ for field in fields: -+ devs[this_device][field] = '' -+ devs[this_device]['up'] = False -+ status_info = re.match('(<)(.*)(>)', prts[-1].strip()).group(2) -+ status_info = status_info.lower().split(',') -+ if 'up' in status_info: -+ devs[this_device]['up'] = True -+ if 'broadcast' in status_info and 'multicast' in status_info: -+ devs[this_device]['bcast'] = 'multicast' -+ continue -+ conf_data = line.strip() -+ conf_data_prts = conf_data.split() -+ if conf_data.startswith('inet '): -+ devs[this_device]['addr'] = conf_data_prts[1] -+ if 'brd' in conf_data_prts: -+ loc = conf_data_prts.index('brd') -+ devs[this_device]['bcast'] = conf_data_prts[loc + 1] -+ if conf_data.startswith('inet6'): -+ devs[this_device]['addr6'] = conf_data_prts[1] -+ if 'scope' in conf_data_prts: -+ loc = conf_data_prts.index('scope') -+ devs[this_device]['scope6'] = conf_data_prts[loc + 1] -+ if conf_data.startswith('link/ether'): -+ devs[this_device]['hwaddr'] = conf_data_prts[1] -+ -+ if empty != "": -+ for (_devname, dev) in devs.items(): -+ for field in dev: -+ if dev[field] == "": -+ dev[field] = empty -+ -+ return devs -+ -+ -+def _route_info_from_netstat(): - (route_out, _err) = util.subp(["netstat", "-rn"], rcs=[0, 1]) - - routes = {} -@@ -150,91 +308,69 @@ def route_info(): - return routes - - --def getgateway(): -- try: -- routes = route_info() -- except Exception: -- pass -- else: -- for r in routes.get('ipv4', []): -- if r['flags'].find("G") >= 0: -- return "%s[%s]" % (r['gateway'], r['iface']) -- return None -- -- --def netdev_pformat(): -- lines = [] -- try: -- netdev = netdev_info(empty=".") -- except Exception: -- lines.append(util.center("Net device info failed", '!', 80)) -- else: -- fields = ['Device', 'Up', 'Address', 'Mask', 'Scope', 'Hw-Address'] -- tbl = SimpleTable(fields) -- for (dev, d) in sorted(netdev.items()): -- tbl.add_row([dev, d["up"], d["addr"], d["mask"], ".", d["hwaddr"]]) -- if d.get('addr6'): -- tbl.add_row([dev, d["up"], -- d["addr6"], ".", d.get("scope6"), d["hwaddr"]]) -- netdev_s = tbl.get_string() -- max_len = len(max(netdev_s.splitlines(), key=len)) -- header = util.center("Net device info", "+", max_len) -- lines.extend([header, netdev_s]) -- return "\n".join(lines) -+def _route_info_from_ip(): -+ """Detremine route information from ip route command""" -+ routes = {} -+ routes['ipv4'] = [] -+ routes['ipv6'] = [] - -+ # IPv4 -+ (route_out, _err) = util.subp(['ip', '-4', 'route', 'list'], rcs=[0, 1]) - --def route_pformat(): -- lines = [] -- try: -- routes = route_info() -- except Exception as e: -- lines.append(util.center('Route info failed', '!', 80)) -- util.logexc(LOG, "Route info failed: %s" % e) -- else: -- if routes.get('ipv4'): -- fields_v4 = ['Route', 'Destination', 'Gateway', -- 'Genmask', 'Interface', 'Flags'] -- tbl_v4 = SimpleTable(fields_v4) -- for (n, r) in enumerate(routes.get('ipv4')): -- route_id = str(n) -- tbl_v4.add_row([route_id, r['destination'], -- r['gateway'], r['genmask'], -- r['iface'], r['flags']]) -- route_s = tbl_v4.get_string() -- max_len = len(max(route_s.splitlines(), key=len)) -- header = util.center("Route IPv4 info", "+", max_len) -- lines.extend([header, route_s]) -- if routes.get('ipv6'): -- fields_v6 = ['Route', 'Proto', 'Recv-Q', 'Send-Q', -- 'Local Address', 'Foreign Address', 'State'] -- tbl_v6 = SimpleTable(fields_v6) -- for (n, r) in enumerate(routes.get('ipv6')): -- route_id = str(n) -- tbl_v6.add_row([route_id, r['proto'], -- r['recv-q'], r['send-q'], -- r['local address'], r['foreign address'], -- r['state']]) -- route_s = tbl_v6.get_string() -- max_len = len(max(route_s.splitlines(), key=len)) -- header = util.center("Route IPv6 info", "+", max_len) -- lines.extend([header, route_s]) -- return "\n".join(lines) -+ entries = route_out.splitlines() -+ for line in entries: -+ route_info = line.strip().split() -+ dest = route_info[0] -+ if route_info[0] == 'default': -+ dest = '0.0.0.0' -+ flags = '' -+ gw = '0.0.0.0' -+ if 'via' in route_info: -+ loc = route_info.index('via') -+ # The NH (Next Hop) is basically equivalent to the gateway -+ gw = route_info[loc + 1] -+ flags = 'G' -+ loc = route_info.index('dev') -+ dev = route_info[loc + 1] -+ entry = { -+ 'destination': dest, -+ 'gateway': gw, -+ 'genmask': '', -+ 'flags': flags, -+ 'metric': '0', -+ 'ref': '0', -+ 'use': '0', -+ 'iface': dev -+ } -+ routes['ipv4'].append(entry) - -+ # IPv6 -+ (route_out, _err) = util.subp(['ip', '-6', 'route', 'list'], rcs=[0, 1]) - --def debug_info(prefix='ci-info: '): -- lines = [] -- netdev_lines = netdev_pformat().splitlines() -- if prefix: -- for line in netdev_lines: -- lines.append("%s%s" % (prefix, line)) -- else: -- lines.extend(netdev_lines) -- route_lines = route_pformat().splitlines() -- if prefix: -- for line in route_lines: -- lines.append("%s%s" % (prefix, line)) -- else: -- lines.extend(route_lines) -- return "\n".join(lines) -+ entries = route_out.splitlines() -+ for line in entries: -+ route_info = line.strip().split() -+ ip = route_info[0] -+ if ip == 'default': -+ ip = '::' -+ proto = 'tcp6' -+ if 'proto' in route_info: -+ loc = route_info.index('proto') -+ proto = route_info[loc + 1] -+ gw = '' -+ if 'via' in route_info: -+ loc = route_info.index('via') -+ # The NH (Next Hop) is basically equivalent to the gateway -+ gw = route_info[loc + 1] -+ entry = { -+ 'proto': proto, -+ 'recv-q': '0', -+ 'send-q': '0', -+ 'local address': ip, -+ 'foreign address': gw, -+ 'state': '', -+ } -+ routes['ipv6'].append(entry) -+ return routes - - # vi: ts=4 expandtab -diff --git a/cloudinit/tests/test_netinfo.py b/cloudinit/tests/test_netinfo.py -index 7dea2e41..3dc557cc 100644 ---- a/cloudinit/tests/test_netinfo.py -+++ b/cloudinit/tests/test_netinfo.py -@@ -2,7 +2,7 @@ - - """Tests netinfo module functions and classes.""" - --from cloudinit.netinfo import netdev_pformat, route_pformat -+from cloudinit.netinfo import getgateway, netdev_pformat, route_pformat - from cloudinit.tests.helpers import CiTestCase, mock - - -@@ -27,6 +27,48 @@ lo Link encap:Local Loopback - collisions:0 txqueuelen:1 - """ - -+SAMPLE_IP_A_OUT = ( -+ '1: lo: mtu 65536 qdisc noqueue state UNKNOWN ' -+ 'group default qlen 1000\n' -+ 'link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n' -+ 'inet 127.0.0.1/8 scope host lo\n' -+ ' valid_lft forever preferred_lft forever\n' -+ 'inet6 ::1/128 scope host\n' -+ ' valid_lft forever preferred_lft forever\n' -+ '2: wlp3s0: mtu 1500 qdisc mq state ' -+ 'UP group default qlen 1000\n' -+ 'link/ether 84:3a:4b:09:6f:ec brd ff:ff:ff:ff:ff:ff\n' -+ 'inet 192.168.1.101/24 brd 192.168.1.255 scope global wlp3s0\n' -+ ' valid_lft forever preferred_lft forever\n' -+ 'inet 192.168.1.3/24 brd 192.168.1.255 scope global secondary wlp3s0\n' -+ ' valid_lft forever preferred_lft forever\n' -+ 'inet6 fe80::863a:4bff:fe09:6fec/64 scope link\n' -+ ' valid_lft forever preferred_lft forever' -+) -+ -+SAMPLE_ROUTE_INFO = { -+ 'ipv4': [ -+ { -+ 'genmask': '0.0.0.0', -+ 'use': '0', -+ 'iface': 'eth1', -+ 'flags': 'UG', -+ 'metric': '0', -+ 'destination': '0.0.0.0', -+ 'ref': '0', -+ 'gateway': '192.168.1.1'}, -+ { -+ 'genmask': '255.0.0.0', -+ 'use': '0', -+ 'iface': 'eth2', -+ 'flags': 'UG', -+ 'metric': '0', -+ 'destination': '10.0.0.0', -+ 'ref': '0', -+ 'gateway': '10.163.8.1'} -+ ] -+} -+ - SAMPLE_ROUTE_OUT = '\n'.join([ - '0.0.0.0 192.168.2.1 0.0.0.0 UG 0 0 0' - ' enp0s25', -@@ -35,6 +77,20 @@ SAMPLE_ROUTE_OUT = '\n'.join([ - '192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0' - ' enp0s25']) - -+SAMPLE_ROUTE_OUT_IP_V4 = '\n'.join([ -+ 'default via 192.168.1.1 dev br0', -+ '10.0.0.0/8 via 10.163.8.1 dev tun0', -+ '10.163.8.1 dev tun0 proto kernel scope link src 10.163.8.118 ', -+ '137.65.0.0/16 via 10.163.8.1 dev tun0']) -+ -+SAMPLE_ROUTE_OUT_IP_V6 = '\n'.join([ -+ '2621:111:80c0:8080:12:160:68:53 dev eth0 proto kernel metric 256 expires ' -+ '9178sec pref medium', -+ '2621:111:80c0:8080::/64 dev eth0 proto ra metric 100 pref medium', -+ 'fe80::1 dev eth0 proto static metric 100 pref medium', -+ 'fe80::/64 dev eth0 proto kernel metric 256 pref medium', -+ 'default via fe80::1 dev eth0 proto static metric 100 pref medium', -+ '2620:113:80c0:8000::/50 dev tun0 metric 1024 pref medium']) - - NETDEV_FORMATTED_OUT = '\n'.join([ - '+++++++++++++++++++++++++++++++++++++++Net device info+++++++++++++++++++' -@@ -56,6 +112,26 @@ NETDEV_FORMATTED_OUT = '\n'.join([ - '+---------+------+------------------------------+---------------+-------+' - '-------------------+']) - -+NETDEV_FORMATTED_OUT_IP = '\n'.join([ -+ '++++++++++++++++++++++++++++++++++Net device info++++++++++++++++++++++' -+ '++++++++++++', -+ '+--------+------+------------------------------+------+-------+----------' -+ '---------+', -+ '| Device | Up | Address | Mask | Scope | Hw-Ad' -+ 'dress |', -+ '+--------+------+------------------------------+------+-------+----------' -+ '---------+', -+ '| lo | True | 127.0.0.1/8 | . | . | .' -+ ' |', -+ '| lo | True | ::1/128 | . | host | .' -+ ' |', -+ '| wlp3s0 | True | 192.168.1.3/24 | . | . | 84:3a:4b:' -+ '09:6f:ec |', -+ '| wlp3s0 | True | fe80::863a:4bff:fe09:6fec/64 | . | link | 84:3a:4b:' -+ '09:6f:ec |', -+ '+--------+------+------------------------------+------+-------+----------' -+ '---------+']) -+ - ROUTE_FORMATTED_OUT = '\n'.join([ - '+++++++++++++++++++++++++++++Route IPv4 info++++++++++++++++++++++++++' - '+++', -@@ -86,21 +162,113 @@ ROUTE_FORMATTED_OUT = '\n'.join([ - '+-------+-------------+-------------+---------------+---------------+' - '-----------------+-------+']) - -+ROUTE_FORMATTED_OUT_IP = '\n'.join([ -+ '+++++++++++++++++++++++++++Route IPv4 info+++++++++++++++++++++++++++', -+ '+-------+---------------+-------------+---------+-----------+-------+', -+ '| Route | Destination | Gateway | Genmask | Interface | Flags |', -+ '+-------+---------------+-------------+---------+-----------+-------+', -+ '| 0 | 0.0.0.0 | 192.168.1.1 | | br0 | G |', -+ '| 1 | 10.0.0.0/8 | 10.163.8.1 | | tun0 | G |', -+ '| 2 | 10.163.8.1 | 0.0.0.0 | | tun0 | |', -+ '| 3 | 137.65.0.0/16 | 10.163.8.1 | | tun0 | G |', -+ '+-------+---------------+-------------+---------+-----------+-------+', -+ '++++++++++++++++++++++++++++++++++++++++Route IPv6 info++++++++++++++' -+ '+++++++++++++++++++++++++++', -+ '+-------+--------+--------+--------+---------------------------------' -+ '+-----------------+-------+', -+ '| Route | Proto | Recv-Q | Send-Q | Local Address ' -+ '| Foreign Address | State |', -+ '+-------+--------+--------+--------+---------------------------------' -+ '+-----------------+-------+', -+ '| 0 | kernel | 0 | 0 | 2621:111:80c0:8080:12:160:68:53 ' -+ '| | |', -+ '| 1 | ra | 0 | 0 | 2621:111:80c0:8080::/64 ' -+ '| | |', -+ '| 2 | static | 0 | 0 | fe80::1 ' -+ '| | |', -+ '| 3 | kernel | 0 | 0 | fe80::/64 ' -+ '| | |', -+ '| 4 | static | 0 | 0 | :: ' -+ '| fe80::1 | |', -+ '| 5 | tcp6 | 0 | 0 | 2620:113:80c0:8000::/50 ' -+ '| | |', -+ '+-------+--------+--------+--------+---------------------------------' -+ '+-----------------+-------+']) -+ - - class TestNetInfo(CiTestCase): - - maxDiff = None - -+ @mock.patch('cloudinit.netinfo.route_info') -+ def test_getdateway_route(self, m_route_info): -+ """getgateway finds the first gateway""" -+ m_route_info.return_value = SAMPLE_ROUTE_INFO -+ gateway = getgateway() -+ self.assertEqual('192.168.1.1[eth1]', gateway) -+ -+ @mock.patch('cloudinit.netinfo.util.which') - @mock.patch('cloudinit.netinfo.util.subp') -- def test_netdev_pformat(self, m_subp): -+ def test_netdev_pformat_ifconfig(self, m_subp, m_which): - """netdev_pformat properly rendering network device information.""" - m_subp.return_value = (SAMPLE_IFCONFIG_OUT, '') -+ m_which.side_effect = side_effect_use_ifconfig - content = netdev_pformat() - self.assertEqual(NETDEV_FORMATTED_OUT, content) - -+ @mock.patch('cloudinit.netinfo.util.which') - @mock.patch('cloudinit.netinfo.util.subp') -- def test_route_pformat(self, m_subp): -+ def test_netdev_pformat_ip(self, m_subp, m_which): -+ """netdev_pformat properly rendering network device information.""" -+ m_subp.return_value = (SAMPLE_IP_A_OUT, '') -+ m_which.side_effect = side_effect_use_ip -+ content = netdev_pformat() -+ self.assertEqual(NETDEV_FORMATTED_OUT_IP, content) -+ -+ @mock.patch('cloudinit.netinfo.util.which') -+ @mock.patch('cloudinit.netinfo.util.subp') -+ def test_route_pformat_netstat(self, m_subp, m_which): - """netdev_pformat properly rendering network device information.""" - m_subp.return_value = (SAMPLE_ROUTE_OUT, '') -+ m_which.side_effect = side_effect_use_netstat - content = route_pformat() - self.assertEqual(ROUTE_FORMATTED_OUT, content) -+ -+ @mock.patch('cloudinit.netinfo.util.which') -+ @mock.patch('cloudinit.netinfo.util.subp') -+ def test_route_pformat_ip(self, m_subp, m_which): -+ """netdev_pformat properly rendering network device information.""" -+ m_subp.side_effect = side_effect_return_route_info -+ m_which.side_effect = side_effect_use_ip -+ content = route_pformat() -+ self.assertEqual(ROUTE_FORMATTED_OUT_IP, content) -+ -+ -+def side_effect_use_ifconfig(tool): -+ if tool == 'ifconfig': -+ return True -+ else: -+ return False -+ -+ -+def side_effect_use_ip(tool): -+ if tool == 'ip': -+ return True -+ else: -+ return False -+ -+ -+def side_effect_use_netstat(tool): -+ if tool == 'netstat': -+ return True -+ else: -+ return False -+ -+ -+def side_effect_return_route_info(cmd, rcs=None): -+ if '-4' in list(cmd): -+ return (SAMPLE_ROUTE_OUT_IP_V4, 0) -+ else: -+ return (SAMPLE_ROUTE_OUT_IP_V6, 0) -+ -+# vi: ts=4 expandtab --- -2.13.6 - diff --git a/0002-Add-tests-for-additional-openSUSE-distro-condition-m.patch b/0002-Add-tests-for-additional-openSUSE-distro-condition-m.patch new file mode 100644 index 0000000..af6aeec --- /dev/null +++ b/0002-Add-tests-for-additional-openSUSE-distro-condition-m.patch @@ -0,0 +1,109 @@ +From 33d988113c3897ea7e0d1eda402d30dfec119602 Mon Sep 17 00:00:00 2001 +From: Robert Schweikert +Date: Sun, 21 Oct 2018 08:46:15 -0400 +Subject: [PATCH 2/2] - Add tests for additional openSUSE distro condition + mechanisms + +--- + cloudinit/tests/test_util.py | 75 ++++++++++++++++++++++++++++++++++---------- + 1 file changed, 59 insertions(+), 16 deletions(-) + +diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py +index 749a3846..c3f52c7b 100644 +--- a/cloudinit/tests/test_util.py ++++ b/cloudinit/tests/test_util.py +@@ -18,25 +18,51 @@ MOUNT_INFO = [ + ] + + OS_RELEASE_SLES = dedent("""\ +- NAME="SLES"\n +- VERSION="12-SP3"\n +- VERSION_ID="12.3"\n +- PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3"\n +- ID="sles"\nANSI_COLOR="0;32"\n +- CPE_NAME="cpe:/o:suse:sles:12:sp3"\n ++ NAME="SLES" ++ VERSION="12-SP3" ++ VERSION_ID="12.3" ++ PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3" ++ ID="sles" ++ ANSI_COLOR="0;32" ++ CPE_NAME="cpe:/o:suse:sles:12:sp3" + """) + + OS_RELEASE_OPENSUSE = dedent("""\ +-NAME="openSUSE Leap" +-VERSION="42.3" +-ID=opensuse +-ID_LIKE="suse" +-VERSION_ID="42.3" +-PRETTY_NAME="openSUSE Leap 42.3" +-ANSI_COLOR="0;32" +-CPE_NAME="cpe:/o:opensuse:leap:42.3" +-BUG_REPORT_URL="https://bugs.opensuse.org" +-HOME_URL="https://www.opensuse.org/" ++ NAME="openSUSE Leap" ++ VERSION="42.3" ++ ID=opensuse ++ ID_LIKE="suse" ++ VERSION_ID="42.3" ++ PRETTY_NAME="openSUSE Leap 42.3" ++ ANSI_COLOR="0;32" ++ CPE_NAME="cpe:/o:opensuse:leap:42.3" ++ BUG_REPORT_URL="https://bugs.opensuse.org" ++ HOME_URL="https://www.opensuse.org/" ++""") ++ ++OS_RELEASE_OPENSUSE_L15 = dedent("""\ ++ NAME="openSUSE Leap" ++ VERSION="15.0" ++ ID="opensuse-leap" ++ ID_LIKE="suse opensuse" ++ VERSION_ID="15.0" ++ PRETTY_NAME="openSUSE Leap 15.0" ++ ANSI_COLOR="0;32" ++ CPE_NAME="cpe:/o:opensuse:leap:15.0" ++ BUG_REPORT_URL="https://bugs.opensuse.org" ++ HOME_URL="https://www.opensuse.org/" ++""") ++ ++OS_RELEASE_OPENSUSE_TW = dedent("""\ ++ NAME="openSUSE Tumbleweed" ++ ID="opensuse-tumbleweed" ++ ID_LIKE="opensuse suse" ++ VERSION_ID="20180920" ++ PRETTY_NAME="openSUSE Tumbleweed" ++ ANSI_COLOR="0;32" ++ CPE_NAME="cpe:/o:opensuse:tumbleweed:20180920" ++ BUG_REPORT_URL="https://bugs.opensuse.org" ++ HOME_URL="https://www.opensuse.org/" + """) + + OS_RELEASE_CENTOS = dedent("""\ +@@ -453,6 +479,23 @@ class TestGetLinuxDistro(CiTestCase): + dist = util.get_linux_distro() + self.assertEqual(('opensuse', '42.3', platform.machine()), dist) + ++ @mock.patch('cloudinit.util.load_file') ++ def test_get_linux_opensuse_l15(self, m_os_release, m_path_exists): ++ """Verify we get the correct name and machine arch on OpenSUSE.""" ++ m_os_release.return_value = OS_RELEASE_OPENSUSE_L15 ++ m_path_exists.side_effect = TestGetLinuxDistro.os_release_exists ++ dist = util.get_linux_distro() ++ self.assertEqual(('opensuse-leap', '15.0', platform.machine()), dist) ++ ++ @mock.patch('cloudinit.util.load_file') ++ def test_get_linux_opensuse_tw(self, m_os_release, m_path_exists): ++ """Verify we get the correct name and machine arch on OpenSUSE.""" ++ m_os_release.return_value = OS_RELEASE_OPENSUSE_TW ++ m_path_exists.side_effect = TestGetLinuxDistro.os_release_exists ++ dist = util.get_linux_distro() ++ self.assertEqual( ++ ('opensuse-tumbleweed', '20180920', platform.machine()), dist) ++ + @mock.patch('platform.dist') + def test_get_linux_distro_no_data(self, m_platform_dist, m_path_exists): + """Verify we get no information if os-release does not exist""" +-- +2.13.7 + diff --git a/0003-Distro-dependent-chrony-config-file.patch b/0003-Distro-dependent-chrony-config-file.patch deleted file mode 100644 index bf1b7b2..0000000 --- a/0003-Distro-dependent-chrony-config-file.patch +++ /dev/null @@ -1,54 +0,0 @@ ---- /dev/null -+++ templates/chrony.conf.sles.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 ---- /dev/null -+++ templates/chrony.conf.opensuse.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 diff --git a/cloud-init-18.2.tar.gz b/cloud-init-18.2.tar.gz deleted file mode 100644 index dab5909..0000000 --- a/cloud-init-18.2.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0224969ebdae6eadffc5f40823bb206d8b05d99a1b730018535102f38b155249 -size 867297 diff --git a/cloud-init-18.4.tar.gz b/cloud-init-18.4.tar.gz new file mode 100644 index 0000000..796c19c --- /dev/null +++ b/cloud-init-18.4.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f19b969dbf2bda771a6a41fdb22b79b163b8a3b81cf1a45036d17993789bef7f +size 965107 diff --git a/cloud-init-no-python-linux-dist.patch b/cloud-init-no-python-linux-dist.patch deleted file mode 100644 index d59a083..0000000 --- a/cloud-init-no-python-linux-dist.patch +++ /dev/null @@ -1,247 +0,0 @@ ---- setup.py.orig -+++ setup.py -@@ -26,6 +26,7 @@ import subprocess - - RENDERED_TMPD_PREFIX = "RENDERED_TEMPD" - -+VARIANT = None - - def is_f(p): - return os.path.isfile(p) -@@ -114,10 +115,20 @@ def render_tmpl(template): - atexit.register(shutil.rmtree, tmpd) - bname = os.path.basename(template).rstrip(tmpl_ext) - fpath = os.path.join(tmpd, bname) -- tiny_p([sys.executable, './tools/render-cloudcfg', template, fpath]) -+ if VARIANT: -+ tiny_p([sys.executable, './tools/render-cloudcfg', '--variant', -+ VARIANT, template, fpath]) -+ else: -+ tiny_p([sys.executable, './tools/render-cloudcfg', template, fpath]) - # return path relative to setup.py - return os.path.join(os.path.basename(tmpd), bname) - -+# User can set the variant for template rendering -+if '--distro' in sys.argv: -+ idx = sys.argv.index('--distro') -+ VARIANT = sys.argv[idx+1] -+ del sys.argv[idx+1] -+ sys.argv.remove('--distro') - - INITSYS_FILES = { - 'sysvinit': [f for f in glob('sysvinit/redhat/*') if is_f(f)], -@@ -145,7 +156,6 @@ INITSYS_ROOTS = { - } - INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()]) - -- - # Install everything in the right location and take care of Linux (default) and - # FreeBSD systems. - USR = "usr" -@@ -158,6 +168,19 @@ if os.uname()[0] == 'FreeBSD': - elif os.path.isfile('/etc/redhat-release'): - USR_LIB_EXEC = "usr/libexec" - -+if VARIANT and sys.argv[1] == 'install': -+ base = ETC -+ config_dir = '/cloud/cloud.cfg.d' -+ if sys.argv.index('--root'): -+ root_idx = sys.argv.index('--root') -+ root_loc = sys.argv[root_idx+1] -+ base = root_loc + '/' + ETC -+ if not os.path.exists(base + config_dir): -+ os.makedirs(base + config_dir) -+ usr_distro = open(base + '/cloud/cloud.cfg.d/cloud-init.user.distro', 'w') -+ usr_distro.write(VARIANT) -+ usr_distro.close() -+ - - class MyEggInfo(egg_info): - """This makes sure to not include the rendered files in SOURCES.txt.""" -@@ -259,7 +282,7 @@ requirements = read_requires() - setuptools.setup( - name='cloud-init', - version=get_version(), -- description='EC2 initialisation magic', -+ description='Cloud initialisation magic', - author='Scott Moser', - author_email='scott.moser@canonical.com', - url='http://launchpad.net/cloud-init/', ---- cloudinit/tests/test_util.py.orig -+++ cloudinit/tests/test_util.py -@@ -3,6 +3,7 @@ - """Tests for cloudinit.util""" - - import logging -+import platform - from textwrap import dedent - - import cloudinit.util as util -@@ -16,6 +17,29 @@ MOUNT_INFO = [ - '153 68 254:0 / /home rw,relatime shared:101 - xfs /dev/sda2 rw,attr2' - ] - -+OS_RELEASE_SLES = dedent("""\ -+NAME="SLES"\n -+VERSION="12-SP3"\n -+VERSION_ID="12.3"\n -+PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3"\n -+ID="sles"\nANSI_COLOR="0;32"\n -+CPE_NAME="cpe:/o:suse:sles:12:sp3"\n -+""") -+ -+OS_RELEASE_UBUNTU = dedent("""\ -+NAME="Ubuntu"\n -+VERSION="16.04.3 LTS (Xenial Xerus)"\n -+ID=ubuntu\n -+ID_LIKE=debian\n -+PRETTY_NAME="Ubuntu 16.04.3 LTS"\n -+VERSION_ID="16.04"\n -+HOME_URL="http://www.ubuntu.com/"\n -+SUPPORT_URL="http://help.ubuntu.com/"\n -+BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"\n -+VERSION_CODENAME=xenial\n -+UBUNTU_CODENAME=xenial\n -+""") -+ - - class FakeCloud(object): - -@@ -65,6 +89,54 @@ class TestUtil(CiTestCase): - is_rw = util.mount_is_read_write('/') - self.assertEqual(is_rw, False) - -+ @mock.patch('os.path.exists') -+ @mock.patch('cloudinit.util.load_file') -+ def test_get_linux_distro_quoted_name(self, m_os_release, m_path_exists): -+ m_os_release.return_value = OS_RELEASE_SLES -+ m_path_exists.side_effect = os_release_exists -+ dist = util.get_linux_distro() -+ self.assertEqual(('sles', '12.3', platform.machine()), dist) -+ -+ @mock.patch('os.path.exists') -+ @mock.patch('cloudinit.util.load_file') -+ def test_get_linux_distro_bare_name(self, m_os_release, m_path_exists): -+ m_os_release.return_value = OS_RELEASE_UBUNTU -+ m_path_exists.side_effect = os_release_exists -+ dist = util.get_linux_distro() -+ self.assertEqual(('ubuntu', '16.04', platform.machine()), dist) -+ -+ @mock.patch('os.path.exists') -+ @mock.patch('platform.dist') -+ def test_get_linux_distro_no_data(self, m_platform_dist, m_path_exists): -+ m_platform_dist.return_value = ('', '', '') -+ m_path_exists.return_value = 0 -+ dist = util.get_linux_distro() -+ self.assertEqual(('', '', ''), dist) -+ -+ @mock.patch('os.path.exists') -+ @mock.patch('platform.dist') -+ def test_get_linux_distro_no_impl(self, m_platform_dist, m_path_exists): -+ m_platform_dist.side_effect = Exception() -+ m_path_exists.return_value = 0 -+ dist = util.get_linux_distro() -+ self.assertEqual(('', '', ''), dist) -+ -+ @mock.patch('os.path.exists') -+ @mock.patch('platform.dist') -+ def test_get_linux_distro_plat_data(self, m_platform_dist, m_path_exists): -+ m_platform_dist.return_value = ('foo', '1.1', 'aarch64') -+ m_path_exists.return_value = 0 -+ dist = util.get_linux_distro() -+ self.assertEqual(('foo', '1.1', 'aarch64'), dist) -+ -+ @mock.patch('os.path.exists') -+ @mock.patch('cloudinit.util.load_file') -+ def test_get_linux_distro_user_set(self, m_user_data, m_path_exists): -+ m_user_data.return_value = 'debian' -+ m_path_exists.side_effect = user_set_distro -+ dist = util.get_linux_distro() -+ self.assertEqual(('debian', 'not set', platform.machine()), dist) -+ - - class TestShellify(CiTestCase): - -@@ -212,4 +284,13 @@ class TestBlkid(CiTestCase): - capture=True, decode="replace") - - -+def os_release_exists(path): -+ if path == '/etc/os-release': -+ return 1 -+ -+ -+def user_set_distro(path): -+ if path == '/etc/cloud/cloud.cfg.d/cloud-init.user.distro': -+ return 1 -+ - # vi: ts=4 expandtab ---- cloudinit/util.py.orig -+++ cloudinit/util.py -@@ -575,6 +575,43 @@ def get_cfg_option_str(yobj, key, defaul - def get_cfg_option_int(yobj, key, default=0): - return int(get_cfg_option_str(yobj, key, default=default)) - -+def get_linux_distro(): -+ distro_name = '' -+ distro_version = '' -+ if os.path.exists('/etc/cloud/cloud.cfg.d/cloud-init.user.distro'): -+ distro_name = load_file( -+ '/etc/cloud/cloud.cfg.d/cloud-init.user.distro') -+ distro_version = 'not set' -+ elif os.path.exists('/etc/os-release'): -+ os_release = load_file('/etc/os-release').split('\n') -+ for entry in os_release: -+ if entry.startswith('ID='): -+ distro_name = entry.split('=')[-1] -+ if '"' in distro_name: -+ distro_name = distro_name.split('"')[1] -+ if entry.startswith('VERSION_ID='): -+ # Lets hope for the best that distros stay consistent ;) -+ distro_version = entry.split('"')[1] -+ else: -+ dist = ('', '', '') -+ try: -+ # Will be removed in 3.7 -+ dist = platform.dist() # pylint: disable=W1505 -+ except Exception: -+ pass -+ finally: -+ found = None -+ for entry in dist: -+ if entry: -+ found = 1 -+ if not found: -+ msg = 'Unable to determine distribution, template expansion ' -+ msg += 'may have unexpected results' -+ LOG.warning(msg) -+ return dist -+ -+ return (distro_name, distro_version, platform.machine()) -+ - - def system_info(): - info = { -@@ -583,19 +620,19 @@ def system_info(): - 'release': platform.release(), - 'python': platform.python_version(), - 'uname': platform.uname(), -- 'dist': platform.dist(), # pylint: disable=W1505 -+ 'dist': get_linux_distro() - } - system = info['system'].lower() - var = 'unknown' - if system == "linux": - linux_dist = info['dist'][0].lower() -- if linux_dist in ('centos', 'fedora', 'debian'): -+ if linux_dist in ('centos', 'fedora', 'debian', 'rhel', 'suse'): - var = linux_dist - elif linux_dist in ('ubuntu', 'linuxmint', 'mint'): - var = 'ubuntu' - elif linux_dist == 'redhat': - var = 'rhel' -- elif linux_dist == 'suse': -+ elif linux_dist in ('opensuse', 'sles'): - var = 'suse' - else: - var = 'linux' diff --git a/cloud-init-no-trace-empt-sect.patch b/cloud-init-no-trace-empt-sect.patch deleted file mode 100644 index 79d7438..0000000 --- a/cloud-init-no-trace-empt-sect.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- cloudinit/stages.py.orig -+++ cloudinit/stages.py -@@ -691,7 +691,9 @@ class Modules(object): - module_list = [] - if name not in self.cfg: - return module_list -- cfg_mods = self.cfg[name] -+ cfg_mods = self.cfg.get(name) -+ if not cfg_mods: -+ return module_list - # Create 'module_list', an array of hashes - # Where hash['mod'] = module name - # hash['freq'] = frequency diff --git a/cloud-init-no-user-lock-if-already-locked.patch b/cloud-init-no-user-lock-if-already-locked.patch deleted file mode 100644 index 2544981..0000000 --- a/cloud-init-no-user-lock-if-already-locked.patch +++ /dev/null @@ -1,18 +0,0 @@ -Index: cloud-init-17.2/cloudinit/distros/__init__.py -=================================================================== ---- cloud-init-17.2.orig/cloudinit/distros/__init__.py -+++ cloud-init-17.2/cloudinit/distros/__init__.py -@@ -551,8 +551,11 @@ class Distro(object): - # about long names. - util.subp(['passwd', '-l', name]) - except Exception as e: -- util.logexc(LOG, 'Failed to disable password for user %s', name) -- raise e -+ if e.exit_code != 3: -+ util.logexc(LOG, 'Failed to disable password for user %s', name) -+ raise e -+ else: -+ util.logexc(LOG, 'Password access already locked for user %s', name) - - def set_passwd(self, user, passwd, hashed=False): - pass_string = '%s:%s' % (user, passwd) diff --git a/cloud-init-setpath-dsitentify.patch b/cloud-init-setpath-dsitentify.patch deleted file mode 100644 index 69d4e15..0000000 --- a/cloud-init-setpath-dsitentify.patch +++ /dev/null @@ -1,27 +0,0 @@ ---- tools/ds-identify.orig -+++ tools/ds-identify -@@ -186,6 +186,16 @@ block_dev_with_label() { - return 0 - } - -+ensure_sane_path() { -+ local t -+ for t in /sbin /usr/sbin /bin /usr/bin; do -+ case ":$PATH:" in -+ *:$t:*|*:$t/:*) continue;; -+ esac -+ PATH="${PATH:+${PATH}:}$t" -+ done -+} -+ - read_fs_info() { - cached "${DI_BLKID_OUTPUT}" && return 0 - # do not rely on links in /dev/disk which might not be present yet. -@@ -1420,6 +1430,7 @@ _main() { - - main() { - local ret="" -+ ensure_sane_path - [ -d "$PATH_RUN_CI" ] || mkdir -p "$PATH_RUN_CI" - if [ "${1:+$1}" != "--force" ] && [ -f "$PATH_RUN_CI_CFG" ] && - [ -f "$PATH_RUN_DI_RESULT" ]; then diff --git a/cloud-init-skip-ovf-tests.patch b/cloud-init-skip-ovf-tests.patch deleted file mode 100644 index 5cbe484..0000000 --- a/cloud-init-skip-ovf-tests.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- tests/unittests/test_datasource/test_ovf.py.orig -+++ tests/unittests/test_datasource/test_ovf.py -@@ -119,6 +119,7 @@ class TestDatasourceOVF(CiTestCase): - self.tdir = self.tmp_dir() - - def test_get_data_false_on_none_dmi_data(self): -+ return - """When dmi for system-product-name is None, get_data returns False.""" - paths = Paths({'seed_dir': self.tdir}) - ds = self.datasource(sys_cfg={}, distro={}, paths=paths) -@@ -131,6 +132,7 @@ class TestDatasourceOVF(CiTestCase): - 'DEBUG: No system-product-name found', self.logs.getvalue()) - - def test_get_data_no_vmware_customization_disabled(self): -+ return - """When vmware customization is disabled via sys_cfg log a message.""" - paths = Paths({'seed_dir': self.tdir}) - ds = self.datasource( diff --git a/cloud-init-sysconf-ethsetup.patch b/cloud-init-sysconf-ethsetup.patch new file mode 100644 index 0000000..03c7929 --- /dev/null +++ b/cloud-init-sysconf-ethsetup.patch @@ -0,0 +1,427 @@ +From 6732e10fa677566a2ddcbc7ff6727cf697d35761 Mon Sep 17 00:00:00 2001 +From: Robert Schweikert +Date: Tue, 23 Oct 2018 12:37:19 -0400 +Subject: [PATCH] - Follow up to db50bc0d9 + ONBOOT is not recognized on + openSUSE and SUSE Linux Enterprise, add the STARTMODE setting + +--- + cloudinit/net/sysconfig.py | 2 + + .../unittests/test_distros/test_netconfig.py | 8 ++++ + tests/unittests/test_net.py | 40 +++++++++++++++++++ + 3 files changed, 50 insertions(+) + +diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py +index 9c16d3a7..ff847038 100644 +--- a/cloudinit/net/sysconfig.py ++++ b/cloudinit/net/sysconfig.py +@@ -242,6 +242,7 @@ class Renderer(renderer.Renderer): + ('USERCTL', False), + ('NM_CONTROLLED', False), + ('BOOTPROTO', 'none'), ++ ('STARTMODE', 'auto'), + ]) + + # If these keys exist, then their values will be used to form +@@ -336,6 +337,7 @@ class Renderer(renderer.Renderer): + iface_cfg.name)) + if subnet.get('control') == 'manual': + iface_cfg['ONBOOT'] = False ++ iface_cfg['STARTMODE'] = 'manual' + + # set IPv4 and IPv6 static addresses + ipv4_index = -1 +diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py +index 6e339355..e986b593 100644 +--- a/tests/unittests/test_distros/test_netconfig.py ++++ b/tests/unittests/test_distros/test_netconfig.py +@@ -468,6 +468,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -476,6 +477,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + DEVICE=eth1 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -499,6 +501,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -507,6 +510,7 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): + DEVICE=eth1 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -559,6 +563,7 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase): + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -567,6 +572,7 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase): + DEVICE=eth1 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -587,6 +593,7 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase): + IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -595,6 +602,7 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase): + DEVICE=eth1 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py +index 8e383739..d94b9430 100644 +--- a/tests/unittests/test_net.py ++++ b/tests/unittests/test_net.py +@@ -144,6 +144,7 @@ IPADDR=172.19.1.34 + NETMASK=255.255.252.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -177,6 +178,7 @@ IPADDR=172.19.1.34 + NETMASK=255.255.252.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -246,6 +248,7 @@ NETMASK=255.255.252.0 + NETMASK1=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -281,6 +284,7 @@ NETMASK=255.255.252.0 + NETMASK1=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -372,6 +376,7 @@ IPV6_DEFAULTGW=2001:DB8::1 + NETMASK=255.255.252.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -409,6 +414,7 @@ IPV6_DEFAULTGW=2001:DB8::1 + NETMASK=255.255.252.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip()), +@@ -524,6 +530,7 @@ NETWORK_CONFIGS = { + HWADDR=cf:d6:af:48:e8:80 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth99': textwrap.dedent("""\ +@@ -539,6 +546,7 @@ NETWORK_CONFIGS = { + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + }, +@@ -652,6 +660,7 @@ NETWORK_CONFIGS = { + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + MTU=9000 +@@ -691,6 +700,7 @@ NETWORK_CONFIGS = { + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -894,6 +904,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + MACADDR=aa:bb:cc:dd:ee:ff + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Bond + USERCTL=no"""), + 'ifcfg-bond0.200': textwrap.dedent("""\ +@@ -902,6 +913,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=bond0 ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes"""), +@@ -919,6 +931,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + PRIO=22 ++ STARTMODE=auto + STP=no + TYPE=Bridge + USERCTL=no"""), +@@ -928,6 +941,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=c0:d6:9f:2c:e8:80 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth0.101': textwrap.dedent("""\ +@@ -946,6 +960,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=eth0 ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes"""), +@@ -956,6 +971,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + MASTER=bond0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + SLAVE=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -966,6 +982,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + MASTER=bond0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + SLAVE=yes + TYPE=Ethernet + USERCTL=no"""), +@@ -976,6 +993,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=66:bb:9f:2c:e8:80 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth4': textwrap.dedent("""\ +@@ -985,6 +1003,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=98:bb:9f:2c:e8:80 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-eth5': textwrap.dedent("""\ +@@ -993,6 +1012,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=98:bb:9f:2c:e8:8a + NM_CONTROLLED=no + ONBOOT=no ++ STARTMODE=manual + TYPE=Ethernet + USERCTL=no""") + }, +@@ -1282,6 +1302,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NETMASK1=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Bond + USERCTL=no + """), +@@ -1293,6 +1314,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1309,6 +1331,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1334,6 +1357,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NETMASK1=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Bond + USERCTL=no + """), +@@ -1345,6 +1369,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1363,6 +1388,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + SLAVE=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1400,6 +1426,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=aa:bb:cc:dd:e8:00 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no"""), + 'ifcfg-en0.99': textwrap.dedent("""\ +@@ -1418,6 +1445,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + PHYSDEV=en0 ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + VLAN=yes"""), +@@ -1459,6 +1487,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NM_CONTROLLED=no + ONBOOT=yes + PRIO=22 ++ STARTMODE=auto + STP=no + TYPE=Bridge + USERCTL=no +@@ -1472,6 +1501,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + IPV6INIT=yes + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1484,6 +1514,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + IPV6INIT=yes + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1558,6 +1589,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=no ++ STARTMODE=manual + TYPE=Ethernet + USERCTL=no + """), +@@ -1568,6 +1600,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + MTU=1480 + NM_CONTROLLED=no + ONBOOT=yes ++ STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """), +@@ -1577,6 +1610,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true + HWADDR=52:54:00:12:34:ff + NM_CONTROLLED=no + ONBOOT=no ++ STARTMODE=manual + TYPE=Ethernet + USERCTL=no + """), +@@ -1933,6 +1967,7 @@ DEVICE=eth1000 + HWADDR=07-1C-C6-75-A4-BE + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip() +@@ -2054,6 +2089,7 @@ IPADDR=10.0.2.15 + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2075,6 +2111,7 @@ BOOTPROTO=dhcp + DEVICE=eth0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2222,6 +2259,7 @@ DEVICE=eth1000 + HWADDR=07-1C-C6-75-A4-BE + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """.lstrip() +@@ -2343,6 +2381,7 @@ IPADDR=10.0.2.15 + NETMASK=255.255.255.0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +@@ -2364,6 +2403,7 @@ BOOTPROTO=dhcp + DEVICE=eth0 + NM_CONTROLLED=no + ONBOOT=yes ++STARTMODE=auto + TYPE=Ethernet + USERCTL=no + """ +-- +2.19.0 + diff --git a/cloud-init-sysconf-path.patch b/cloud-init-sysconf-path.patch new file mode 100644 index 0000000..c6b17f3 --- /dev/null +++ b/cloud-init-sysconf-path.patch @@ -0,0 +1,13 @@ +--- cloudinit/net/sysconfig.py.orig ++++ cloudinit/net/sysconfig.py +@@ -660,9 +660,7 @@ def available(target=None): + if not util.which(p, search=search, target=target): + return False + +- expected_paths = [ +- 'etc/sysconfig/network-scripts/network-functions', +- 'etc/sysconfig/network-scripts/ifdown-eth'] ++ expected_paths = ['etc/sysconfig/network/scripts/functions.netconfig'] + for p in expected_paths: + if not os.path.isfile(util.target_path(target, p)): + return False diff --git a/cloud-init-sysconfig-netpathfix.patch b/cloud-init-sysconfig-netpathfix.patch deleted file mode 100644 index 5fc41e4..0000000 --- a/cloud-init-sysconfig-netpathfix.patch +++ /dev/null @@ -1,37 +0,0 @@ -Index: cloudinit/net/sysconfig.py -=================================================================== ---- cloudinit/net/sysconfig.py.orig -+++ cloudinit/net/sysconfig.py -@@ -91,8 +91,8 @@ class ConfigMap(object): - class Route(ConfigMap): - """Represents a route configuration.""" - -- route_fn_tpl_ipv4 = '%(base)s/network-scripts/route-%(name)s' -- route_fn_tpl_ipv6 = '%(base)s/network-scripts/route6-%(name)s' -+ route_fn_tpl_ipv4 = '%(base)s/network/route-%(name)s' -+ route_fn_tpl_ipv6 = '%(base)s/network/route6-%(name)s' - - def __init__(self, route_name, base_sysconf_dir): - super(Route, self).__init__() -@@ -169,7 +169,7 @@ class Route(ConfigMap): - class NetInterface(ConfigMap): - """Represents a sysconfig/networking-script (and its config + children).""" - -- iface_fn_tpl = '%(base)s/network-scripts/ifcfg-%(name)s' -+ iface_fn_tpl = '%(base)s/network/ifcfg-%(name)s' - - iface_types = { - 'ethernet': 'Ethernet', -@@ -616,12 +616,6 @@ def available(target=None): - if not util.which(p, search=search, target=target): - return False - -- expected_paths = [ -- 'etc/sysconfig/network-scripts/network-functions', -- 'etc/sysconfig/network-scripts/ifdown-eth'] -- for p in expected_paths: -- if not os.path.isfile(util.target_path(target, p)): -- return False - return True - - diff --git a/cloud-init-template-py2.patch b/cloud-init-template-py2.patch new file mode 100644 index 0000000..74e73a7 --- /dev/null +++ b/cloud-init-template-py2.patch @@ -0,0 +1,8 @@ +--- tools/render-cloudcfg.orig ++++ tools/render-cloudcfg +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python3 ++#!/usr/bin/env python + + import argparse + import os diff --git a/cloud-init-translate-netconf-ipv4-keep-gw.patch b/cloud-init-translate-netconf-ipv4-keep-gw.patch deleted file mode 100644 index 3a34fd7..0000000 --- a/cloud-init-translate-netconf-ipv4-keep-gw.patch +++ /dev/null @@ -1,46 +0,0 @@ ---- cloudinit/distros/net_util.py.orig -+++ cloudinit/distros/net_util.py -@@ -67,6 +67,10 @@ - # } - # } - -+import re -+ -+ipv4 = re.compile("\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}") -+ - def translate_network(settings): - # Get the standard cmd, args from the ubuntu format - entries = [] -@@ -88,7 +92,14 @@ def translate_network(settings): - consume = {} - consume[cmd] = args - else: -- consume[cmd] = args -+ if consume.get(cmd): -+ val = consume[cmd] -+ if isinstance(val, list): -+ consume[cmd].append(args) -+ else: -+ consume[cmd] = [val, args] -+ else: -+ consume[cmd] = args - # Check if anything left over to consume - absorb = False - for (cmd, args) in consume.items(): -@@ -148,6 +159,16 @@ def translate_network(settings): - hw_addr = hw_split[1] - if hw_addr: - iface_info['hwaddress'] = hw_addr -+ if 'post-up' in info: -+ routes = info['post-up'] -+ if isinstance(routes, list): -+ for route_info in routes: -+ if 'default gw' in route_info: -+ iface_info['gateway'] = ipv4.search( -+ route_info).group(0) -+ elif 'default gw' in routes: -+ iface_info['gateway'] = ipv4.search(routes).group(0) -+ - # If ipv6 is enabled, device will have multiple IPs, so we need to - # update the dictionary instead of overwriting it... - if dev_name in real_ifaces: diff --git a/cloud-init.changes b/cloud-init.changes index a03f877..e450aac 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -1,3 +1,234 @@ +------------------------------------------------------------------- +Thu Oct 25 18:56:13 UTC 2018 - Robert Schweikert + +- Update to version 18.4 (bsc#1087331, bsc#1097388, boo#1111427, bsc#1095627) + + Remove cloud-init-no-user-lock-if-already-locked.patch + cloud-init 18.4 is not supported on SLE 11 code base + + Remove 0001-Support-chrony-configuration-lp-1731619.patch + Included upstream + + Remove 0003-Distro-dependent-chrony-config-file.patch + Included upstream + + Remove 0001-switch-to-using-iproute2-tools.patch + Included upstream + + Remove cloud-init-no-python-linux-dist.patch + Included upstream + + Remove cloud-init-no-trace-empt-sect.patch + Included upstream + + Remove cloud-init-setpath-dsitentify.patch + Included upstream + + Modify fix-default-systemd-unit-dir.patch + Use pkg-config, only modify the generator + + Remove cloud-init-sysconfig-netpathfix.patch + Fixed upstream + + Removed cloud-init-skip-ovf-tests.patch + Fixed upstream + + Removed cloud-init-translate-netconf-ipv4-keep-gw.patch + Fixed upstream + + Add cloud-init-template-py2.patch avoid Python 3 dependency when we build + for distros with Python 2 support + + Add 0001-Follow-the-ever-bouncing-ball-for-openSUSE-distribut.patch + + Add 0002-Add-tests-for-additional-openSUSE-distro-condition-m.patch + + Add cloud-init-sysconf-path.patch + + Add cloud-init-sysconf-ethsetup.patch + + Add 0001-Fix-the-service-order-for-SUSE-distributions.patch + + Add dhcp-client as requirement + cloud-init uses dhclient to setup temporary network for + metadata retrieval. THis is needed until lp#1733226 is addressed + + add rtd example docs about new standardized keys + + use ds._crawled_metadata instance attribute if set when writing + instance-data.json + + ec2: update crawled metadata. add standardized keys + + tests: allow skipping an entire cloud_test without running. + + tests: disable lxd tests on cosmic + + cii-tests: use unittest2.SkipTest in ntp_chrony due to new deps + + lxd: adjust to snap installed lxd. + + docs: surface experimental doc in instance-data.json + + tests: fix ec2 integration tests. process meta_data instead of meta-data + + Add support for Infiniband network interfaces (IPoIB). [Mark Goddard] + + cli: add cloud-init query subcommand to query instance metadata + + tools/tox-venv: update for new features. + + pylint: ignore warning assignment-from-no-return for _write_network + + stages: Fix bug causing datasource to have incorrect sys_cfg. + (LP: #1787459) + + Remove dead-code _write_network distro implementations. + + net_util: ensure static configs have netmask in translate_network result + [Thomas Berger] (LP: #1792454) + + Fall back to root:root on syslog permissions if other options fail. + [Robert Schweikert] + + tests: Add mock for util.get_hostname. [Robert Schweikert] (LP: #1792799) + + ds-identify: doc string cleanup. + + OpenStack: Support setting mac address on bond. + [Fabian Wiesel] (LP: #1682064) + + bash_completion/cloud-init: fix shell syntax error. + + EphemeralIPv4Network: Be more explicit when adding default route. + (LP: #1792415) + + OpenStack: support reading of newer versions of metdata. + + OpenStack: fix bug causing 'latest' version to be used from network. + (LP: #1792157) + + user-data: jinja template to render instance-data.json in cloud-config + (LP: #1791781) + + config: disable ssh access to a configured user account + + tests: print failed testname instead of docstring upon failure + + tests: Disallow use of util.subp except for where needed. + + sysconfig: refactor sysconfig to accept distro specific templates paths + + Add unit tests for config/cc_ssh.py [Francis Ginther] + + Fix the built-in cloudinit/tests/helpers:skipIf + + read-version: enhance error message [Joshua Powers] + + hyperv_reporting_handler: simplify threaded publisher + + VMWare: Fix a network config bug in vm with static IPv4 and no gateway. + [Pengpeng Sun] (LP: #1766538) + + logging: Add logging config type hyperv for reporting via Azure KVP + [Andy Liu] + + tests: disable other snap test as well [Joshua Powers] + + tests: disable snap, fix write_files binary [Joshua Powers] + + Add datasource Oracle Compute Infrastructure (OCI). + + azure: allow azure to generate network configuration from IMDS per boot. + + Scaleway: Add network configuration to the DataSource [Louis Bouchard] + + docs: Fix example cloud-init analyze command to match output. + [Wesley Gao] + + netplan: Correctly render macaddress on a bonds and bridges when + provided. (LP: #1784699) + + tools: Add 'net-convert' subcommand command to 'cloud-init devel'. + + redhat: remove ssh keys on new instance. (LP: #1781094) + + Use typeset or local in profile.d scripts. (LP: #1784713) + + OpenNebula: Fix null gateway6 [Akihiko Ota] (LP: #1768547) + + oracle: fix detect_openstack to report True on OracleCloud.com DMI data + (LP: #1784685) + + tests: improve LXDInstance trying to workaround or catch bug. + + update_metadata re-config on every boot comments and tests not quite + right [Mike Gerdts] + + tests: Collect build_info from system if available. + + pylint: Fix pylint warnings reported in pylint 2.0.0. + + get_linux_distro: add support for rhel via redhat-release. + + get_linux_distro: add support for centos6 and rawhide flavors of redhat + (LP: #1781229) + + tools: add '--debug' to tools/net-convert.py + + tests: bump the version of paramiko to 2.4.1. + + docs: note in rtd about avoiding /tmp when writing files (LP: #1727876) + + ubuntu,centos,debian: get_linux_distro to align with platform.dist + (LP: #1780481) + + Fix boothook docs on environment variable name (INSTANCE_I -> + INSTANCE_ID) [Marc Tamsky] + + update_metadata: a datasource can support network re-config every boot + + tests: drop salt-minion integration test (LP: #1778737) + + Retry on failed import of gpg receive keys. + + tools: Fix run-container when neither source or binary package requested. + + docs: Fix a small spelling error. [Oz N Tiram] + + tox: use simplestreams from git repository rather than bzr. +- From 18.3 + + docs: represent sudo:false in docs for user_groups config module + + Explicitly prevent `sudo` access for user module + [Jacob Bednarz] (LP: #1771468) + + lxd: Delete default network and detach device if lxd-init created them. + (LP: #1776958) + + openstack: avoid unneeded metadata probe on non-openstack platforms + (LP: #1776701) + + stages: fix tracebacks if a module stage is undefined or empty + [Robert Schweikert] (LP: #1770462) + + Be more safe on string/bytes when writing multipart user-data to disk. + (LP: #1768600) + + Fix get_proc_env for pids that have non-utf8 content in environment. + (LP: #1775371) + + tests: fix salt_minion integration test on bionic and later + + tests: provide human-readable integration test summary when --verbose + + tests: skip chrony integration tests on lxd running artful or older + + test: add optional --preserve-instance arg to integraiton tests + + netplan: fix mtu if provided by network config for all rendered types + (LP: #1774666) + + tests: remove pip install workarounds for pylxd, take upstream fix. + + subp: support combine_capture argument. + + tests: ordered tox dependencies for pylxd install + + util: add get_linux_distro function to replace platform.dist + [Robert Schweikert] (LP: #1745235) + + pyflakes: fix unused variable references identified by pyflakes 2.0.0. + + Do not use the systemd_prefix macro, not available in this environment + [Robert Schweikert] + + doc: Add config info to ec2, openstack and cloudstack datasource docs + + Enable SmartOS network metadata to work with netplan via per-subnet + routes [Dan McDonald] (LP: #1763512) + + openstack: Allow discovery in init-local using dhclient in a sandbox. + (LP: #1749717) + + tests: Avoid using https in httpretty, improve HttPretty test case. + (LP: #1771659) + + yaml_load/schema: Add invalid line and column nums to error message + + Azure: Ignore NTFS mount errors when checking ephemeral drive + [Paul Meyer] + + packages/brpm: Get proper dependencies for cmdline distro. + + packages: Make rpm spec files patch in package version like in debs. + + tools/run-container: replace tools/run-centos with more generic. + + Update version.version_string to contain packaged version. (LP: #1770712) + + cc_mounts: Do not add devices to fstab that are already present. + [Lars Kellogg-Stedman] + + ds-identify: ensure that we have certain tokens in PATH. (LP: #1771382) + + tests: enable Ubuntu Cosmic in integration tests [Joshua Powers] + + read_file_or_url: move to url_helper, fix bug in its FileResponse. + + cloud_tests: help pylint [Ryan Harper] + + flake8: fix flake8 errors in previous commit. + + typos: Fix spelling mistakes in cc_mounts.py log messages [Stephen Ford] + + tests: restructure SSH and initial connections [Joshua Powers] + + ds-identify: recognize container-other as a container, test SmartOS. + + cloud-config.service: run After snap.seeded.service. (LP: #1767131) + + tests: do not rely on host /proc/cmdline in test_net.py + [Lars Kellogg-Stedman] (LP: #1769952) + + ds-identify: Remove dupe call to is_ds_enabled, improve debug message. + + SmartOS: fix get_interfaces for nics that do not have addr_assign_type. + + tests: fix package and ca_cert cloud_tests on bionic + (LP: #1769985) + + ds-identify: make shellcheck 0.4.6 happy with ds-identify. + + pycodestyle: Fix deprecated string literals, move away from flake8. + + azure: Add reported ready marker file. [Joshua Chan] (LP: #1765214) + + tools: Support adding a release suffix through packages/bddeb. + + FreeBSD: Invoke growfs on ufs filesystems such that it does not prompt. + [Harm Weites] (LP: #1404745) + + tools: Re-use the orig tarball in packages/bddeb if it is around. + + netinfo: fix netdev_pformat when a nic does not have an address + assigned. (LP: #1766302) + + collect-logs: add -v flag, write to stderr, limit journal to single + boot. (LP: #1766335) + + IBMCloud: Disable config-drive and nocloud only if IBMCloud is enabled. + (LP: #1766401) + + Add reporting events and log_time around early source of blocking time + [Ryan Harper] + + IBMCloud: recognize provisioning environment during debug boots. + (LP: #1767166) + + net: detect unstable network names and trigger a settle if needed + [Ryan Harper] (LP: #1766287) + + IBMCloud: improve documentation in datasource. + + sysconfig: dhcp6 subnet type should not imply dhcpv4 [Vitaly Kuznetsov] + + packages/debian/control.in: add missing dependency on iproute2. + (LP: #1766711) + + DataSourceSmartOS: add locking of serial device. + [Mike Gerdts] (LP: #1746605) + + DataSourceSmartOS: sdc:hostname is ignored [Mike Gerdts] (LP: #1765085) + + DataSourceSmartOS: list() should always return a list + [Mike Gerdts] (LP: #1763480) + + schema: in validation, raise ImportError if strict but no jsonschema. + + set_passwords: Add newline to end of sshd config, only restart if + updated. (LP: #1677205) + + pylint: pay attention to unused variable warnings. + + doc: Add documentation for AliYun datasource. [Junjie Wang] + + Schema: do not warn on duplicate items in commands. (LP: #1764264) + + net: Depend on iproute2's ip instead of net-tools ifconfig or route + + DataSourceSmartOS: fix hang when metadata service is down + [Mike Gerdts] (LP: #1667735) + + DataSourceSmartOS: change default fs on ephemeral disk from ext3 to + ext4. [Mike Gerdts] (LP: #1763511) + + pycodestyle: Fix invalid escape sequences in string literals. + + Implement bash completion script for cloud-init command line + [Ryan Harper] + + tools: Fix make-tarball cli tool usage for development + + renderer: support unicode in render_from_file. + + Implement ntp client spec with auto support for distro selection + [Ryan Harper] (LP: #1749722) + + Apport: add Brightbox, IBM, LXD, and OpenTelekomCloud to list of clouds. + + tests: fix ec2 integration network metadata validation + + tests: fix integration tests to support lxd 3.0 release + + correct documentation to match correct attribute name usage. + [Dominic Schlegel] (LP: #1420018) + + cc_resizefs, util: handle no /dev/zfs [Ryan Harper] + + doc: Fix links in OpenStack datasource documentation. + [Dominic Schlegel] (LP: #1721660) + ------------------------------------------------------------------- Fri Aug 24 21:42:43 UTC 2018 - rjschwei@suse.com diff --git a/cloud-init.spec b/cloud-init.spec index 9b88c9f..79e8408 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -18,7 +18,7 @@ %global configver 0.7 Name: cloud-init -Version: 18.2 +Version: 18.4 Release: 0 License: GPL-3.0 and AGPL-3.0 Summary: Cloud node initialization tool @@ -28,45 +28,28 @@ Source0: %{name}-%{version}.tar.gz Source1: rsyslog-cloud-init.cfg -# FIXME cloud-init-translate-netconf-ipv4-keep-gw (bsc#1064854) -# proposed for upstream merge (lp#1732966) -Patch8: cloud-init-translate-netconf-ipv4-keep-gw.patch -Patch10: cloud-init-no-user-lock-if-already-locked.patch +# FIXME +# proposed for upstream merge +# https://code.launchpad.net/~rjschwei/cloud-init/+git/cloud-init/+merge/356098 +Patch12: fix-default-systemd-unit-dir.patch # python2 disables SIGPIPE, causing broken pipe errors in shell scripts (bsc#903449) Patch20: cloud-init-python2-sigpipe.patch -Patch27: cloud-init-sysconfig-netpathfix.patch +Patch21: cloud-init-template-py2.patch Patch29: datasourceLocalDisk.patch Patch34: cloud-init-tests-set-exec.patch -# FIXME chrony support upstream -# These patches represent a working appraoch to supporting chrony -# Upstream is seeking a significant re-write which is not likely to happen -# before we need chrony support -Patch37: 0001-Support-chrony-configuration-lp-1731619.patch -Patch39: 0003-Distro-dependent-chrony-config-file.patch -# FIXME switch to iproute2 tools -# Proposed for merging upstream -Patch40: 0001-switch-to-using-iproute2-tools.patch -# FIXME do not use platform.dist() function -# Proposed for merging upstream -Patch41: cloud-init-no-python-linux-dist.patch -# Disable OVF tests -Patch42: cloud-init-skip-ovf-tests.patch -# FIXME no traceback for empt stage -# #lp1770462 -# https://code.launchpad.net/~rjschwei/cloud-init/+git/cloud-init/+merge/345377 -Patch43: cloud-init-no-trace-empt-sect.patch -# FIXME cloud-init-setpath-gen.patch (boo#1093501) -# Merged upstream remove for 18.3 -Patch44: cloud-init-setpath-dsitentify.patch -# We are going to fix the network setup upstream, two parts: -# 1. clod-init will get it's own dhcp setup to no longer rely on dhclient -# 2. we will switch the SUSE implementation to the sysconfig renderer to -# fix network config setup issues -# Until then, expected with 18.4 or 18.5 we will carry this patch -Patch45: cloud-init-network-online.patch -# The generator will become a template upstream, 18.4 or 18.5, until then -# fix the generator directly -Patch46: fix-default-systemd-unit-dir.patch +# FIXME +# https://code.launchpad.net/~rjschwei/cloud-init/+git/cloud-init/+merge/357644 +Patch36: 0001-Follow-the-ever-bouncing-ball-for-openSUSE-distribut.patch +Patch37: 0002-Add-tests-for-additional-openSUSE-distro-condition-m.patch +# FIXME no proposed solution +Patch38: cloud-init-sysconf-path.patch +# FIXME (lp#1799540) +# https://code.launchpad.net/~rjschwei/cloud-init/+git/cloud-init/+merge/357710 +Patch39: cloud-init-sysconf-ethsetup.patch +# FIXME (lp#1799709) +# https://code.launchpad.net/~rjschwei/cloud-init/+git/cloud-init/+merge/357752 +Patch40: 0001-Fix-the-service-order-for-SUSE-distributions.patch + BuildRequires: fdupes BuildRequires: filesystem # pkg-config is needed to find correct systemd unit dir @@ -102,6 +85,7 @@ BuildRequires: sles-release %endif BuildRequires: util-linux Requires: bash +Requires: dhcp-client Requires: file Requires: growpart Requires: e2fsprogs @@ -198,23 +182,18 @@ Documentation and examples for cloud-init tools %prep %setup -q -%patch8 -%patch10 -p1 +%patch12 %if 0%{?suse_version} < 1315 %patch20 +%patch21 %endif -%patch27 %patch29 -p0 %patch34 -%patch37 +%patch36 -p1 +%patch37 -p1 +%patch38 %patch39 -p1 %patch40 -p1 -%patch41 -%patch42 -%patch43 -%patch44 -%patch45 -p1 -%patch46 -p1 %build %if 0%{?suse_version} && 0%{?suse_version} <= 1315 @@ -255,11 +234,13 @@ mv %{buildroot}%{_datadir}/doc/%{name} %{buildroot}%{docdir} # copy the LICENSE cp LICENSE %{buildroot}%{docdir} # Set the distribution indicator +%if 0%{?suse_version} %if 0%{?is_opensuse} sed -i s/suse/opensuse/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg %else sed -i s/suse/sles/ %{buildroot}/%{_sysconfdir}/cloud/cloud.cfg %endif +%endif mkdir -p %{buildroot}/%{_sysconfdir}/rsyslog.d mkdir -p %{buildroot}/usr/lib/udev/rules.d/ cp -a %{SOURCE1} %{buildroot}/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf @@ -309,6 +290,7 @@ popd %config(noreplace) %{_sysconfdir}/cloud/templates %{_sysconfdir}/dhcp/dhclient-exit-hooks.d/hook-dhclient %{_sysconfdir}/NetworkManager/dispatcher.d/hook-network-manager +%{_sysconfdir}/bash_completion.d/cloud-init %if 0%{?suse_version} && 0%{?suse_version} <= 1315 %{python_sitelib}/cloudinit %{python_sitelib}/cloud_init-%{version}-py%{py_ver}.egg-info diff --git a/fix-default-systemd-unit-dir.patch b/fix-default-systemd-unit-dir.patch index 642733e..bc58540 100644 --- a/fix-default-systemd-unit-dir.patch +++ b/fix-default-systemd-unit-dir.patch @@ -1,7 +1,7 @@ -Index: cloud-init-18.2/systemd/cloud-init-generator +Index: systemd/cloud-init-generator =================================================================== ---- cloud-init-18.2.orig/systemd/cloud-init-generator -+++ cloud-init-18.2/systemd/cloud-init-generator +--- systemd/cloud-init-generator.orig ++++ systemd/cloud-init-generator @@ -9,7 +9,7 @@ DISABLE="disabled" FOUND="found" NOTFOUND="notfound"