SHA256
1
0
forked from pool/cloud-init

- 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

OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/cloud-init?expand=0&rev=121
This commit is contained in:
Robert Schweikert 2018-10-25 18:58:19 +00:00 committed by Git OBS Bridge
parent 6c4efe240a
commit 3ed6919cb4
21 changed files with 890 additions and 1466 deletions

View File

@ -0,0 +1,28 @@
From 1f7950f72dc5f3603118c0f91dca3fb7145f0801 Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
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

View File

@ -0,0 +1,40 @@
From eb504025c76909175ab2d00c25232b89faf01ab4 Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
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

View File

@ -1,272 +0,0 @@
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)

View File

@ -1,682 +0,0 @@
From 48c4dcd464d8c6daccf09b3dccc664ad347b34ce Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
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: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

View File

@ -0,0 +1,109 @@
From 33d988113c3897ea7e0d1eda402d30dfec119602 Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
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

View File

@ -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

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0224969ebdae6eadffc5f40823bb206d8b05d99a1b730018535102f38b155249
size 867297

3
cloud-init-18.4.tar.gz Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f19b969dbf2bda771a6a41fdb22b79b163b8a3b81cf1a45036d17993789bef7f
size 965107

View File

@ -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'

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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(

View File

@ -0,0 +1,427 @@
From 6732e10fa677566a2ddcbc7ff6727cf697d35761 Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -1,3 +1,234 @@
-------------------------------------------------------------------
Thu Oct 25 18:56:13 UTC 2018 - Robert Schweikert <rjschwei@suse.com>
- 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

View File

@ -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

View File

@ -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"