SHA256
1
0
forked from pool/cloud-init

Accepting request 738480 from Cloud:Tools

Automatic submission by obs-autosubmit

OBS-URL: https://build.opensuse.org/request/show/738480
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/cloud-init?expand=0&rev=62
This commit is contained in:
Dominique Leuenberger 2019-10-18 12:30:07 +00:00 committed by Git OBS Bridge
commit 08601df903
6 changed files with 51 additions and 498 deletions

View File

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

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

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

View File

@ -1,426 +0,0 @@
From 07b17236be5665bb552c7460102bcd07bf8f2be8 Mon Sep 17 00:00:00 2001
From: Ryan Harper <ryan.harper@canonical.com>
Date: Tue, 16 Jul 2019 22:40:15 +0000
Subject: net: add rfc3442 (classless static routes) to EphemeralDHCP
The EphemeralDHCP context manager did not parse or handle
rfc3442 classless static routes which prevented reading
datasource metadata in some clouds. This branch adds support
for extracting the field from the leases output, parsing the
format and then adding the required iproute2 ip commands to
apply (and teardown) the static routes.
LP: #1821102
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index e758006..624c9b4 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -679,7 +679,7 @@ class EphemeralIPv4Network(object):
"""
def __init__(self, interface, ip, prefix_or_mask, broadcast, router=None,
- connectivity_url=None):
+ connectivity_url=None, static_routes=None):
"""Setup context manager and validate call signature.
@param interface: Name of the network interface to bring up.
@@ -690,6 +690,7 @@ class EphemeralIPv4Network(object):
@param router: Optionally the default gateway IP.
@param connectivity_url: Optionally, a URL to verify if a usable
connection already exists.
+ @param static_routes: Optionally a list of static routes from DHCP
"""
if not all([interface, ip, prefix_or_mask, broadcast]):
raise ValueError(
@@ -706,6 +707,7 @@ class EphemeralIPv4Network(object):
self.ip = ip
self.broadcast = broadcast
self.router = router
+ self.static_routes = static_routes
self.cleanup_cmds = [] # List of commands to run to cleanup state.
def __enter__(self):
@@ -718,7 +720,21 @@ class EphemeralIPv4Network(object):
return
self._bringup_device()
- if self.router:
+
+ # rfc3442 requires us to ignore the router config *if* classless static
+ # routes are provided.
+ #
+ # https://tools.ietf.org/html/rfc3442
+ #
+ # If the DHCP server returns both a Classless Static Routes option and
+ # a Router option, the DHCP client MUST ignore the Router option.
+ #
+ # Similarly, if the DHCP server returns both a Classless Static Routes
+ # option and a Static Routes option, the DHCP client MUST ignore the
+ # Static Routes option.
+ if self.static_routes:
+ self._bringup_static_routes()
+ elif self.router:
self._bringup_router()
def __exit__(self, excp_type, excp_value, excp_traceback):
@@ -762,6 +778,20 @@ class EphemeralIPv4Network(object):
['ip', '-family', 'inet', 'addr', 'del', cidr, 'dev',
self.interface])
+ def _bringup_static_routes(self):
+ # static_routes = [("169.254.169.254/32", "130.56.248.255"),
+ # ("0.0.0.0/0", "130.56.240.1")]
+ for net_address, gateway in self.static_routes:
+ via_arg = []
+ if gateway != "0.0.0.0/0":
+ via_arg = ['via', gateway]
+ util.subp(
+ ['ip', '-4', 'route', 'add', net_address] + via_arg +
+ ['dev', self.interface], capture=True)
+ self.cleanup_cmds.insert(
+ 0, ['ip', '-4', 'route', 'del', net_address] + via_arg +
+ ['dev', self.interface])
+
def _bringup_router(self):
"""Perform the ip commands to fully setup the router if needed."""
# Check if a default route exists and exit if it does
diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py
index c98a97c..1737991 100644
--- a/cloudinit/net/dhcp.py
+++ b/cloudinit/net/dhcp.py
@@ -92,10 +92,14 @@ class EphemeralDHCPv4(object):
nmap = {'interface': 'interface', 'ip': 'fixed-address',
'prefix_or_mask': 'subnet-mask',
'broadcast': 'broadcast-address',
+ 'static_routes': 'rfc3442-classless-static-routes',
'router': 'routers'}
kwargs = dict([(k, self.lease.get(v)) for k, v in nmap.items()])
if not kwargs['broadcast']:
kwargs['broadcast'] = bcip(kwargs['prefix_or_mask'], kwargs['ip'])
+ if kwargs['static_routes']:
+ kwargs['static_routes'] = (
+ parse_static_routes(kwargs['static_routes']))
if self.connectivity_url:
kwargs['connectivity_url'] = self.connectivity_url
ephipv4 = EphemeralIPv4Network(**kwargs)
@@ -272,4 +276,90 @@ def networkd_get_option_from_leases(keyname, leases_d=None):
return data[keyname]
return None
+
+def parse_static_routes(rfc3442):
+ """ parse rfc3442 format and return a list containing tuple of strings.
+
+ The tuple is composed of the network_address (including net length) and
+ gateway for a parsed static route.
+
+ @param rfc3442: string in rfc3442 format
+ @returns: list of tuple(str, str) for all valid parsed routes until the
+ first parsing error.
+
+ E.g.
+ sr = parse_state_routes("32,169,254,169,254,130,56,248,255,0,130,56,240,1")
+ sr = [
+ ("169.254.169.254/32", "130.56.248.255"), ("0.0.0.0/0", "130.56.240.1")
+ ]
+
+ Python version of isc-dhclient's hooks:
+ /etc/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes
+ """
+ # raw strings from dhcp lease may end in semi-colon
+ rfc3442 = rfc3442.rstrip(";")
+ tokens = rfc3442.split(',')
+ static_routes = []
+
+ def _trunc_error(cidr, required, remain):
+ msg = ("RFC3442 string malformed. Current route has CIDR of %s "
+ "and requires %s significant octets, but only %s remain. "
+ "Verify DHCP rfc3442-classless-static-routes value: %s"
+ % (cidr, required, remain, rfc3442))
+ LOG.error(msg)
+
+ current_idx = 0
+ for idx, tok in enumerate(tokens):
+ if idx < current_idx:
+ continue
+ net_length = int(tok)
+ if net_length in range(25, 33):
+ req_toks = 9
+ if len(tokens[idx:]) < req_toks:
+ _trunc_error(net_length, req_toks, len(tokens[idx:]))
+ return static_routes
+ net_address = ".".join(tokens[idx+1:idx+5])
+ gateway = ".".join(tokens[idx+5:idx+req_toks])
+ current_idx = idx + req_toks
+ elif net_length in range(17, 25):
+ req_toks = 8
+ if len(tokens[idx:]) < req_toks:
+ _trunc_error(net_length, req_toks, len(tokens[idx:]))
+ return static_routes
+ net_address = ".".join(tokens[idx+1:idx+4] + ["0"])
+ gateway = ".".join(tokens[idx+4:idx+req_toks])
+ current_idx = idx + req_toks
+ elif net_length in range(9, 17):
+ req_toks = 7
+ if len(tokens[idx:]) < req_toks:
+ _trunc_error(net_length, req_toks, len(tokens[idx:]))
+ return static_routes
+ net_address = ".".join(tokens[idx+1:idx+3] + ["0", "0"])
+ gateway = ".".join(tokens[idx+3:idx+req_toks])
+ current_idx = idx + req_toks
+ elif net_length in range(1, 9):
+ req_toks = 6
+ if len(tokens[idx:]) < req_toks:
+ _trunc_error(net_length, req_toks, len(tokens[idx:]))
+ return static_routes
+ net_address = ".".join(tokens[idx+1:idx+2] + ["0", "0", "0"])
+ gateway = ".".join(tokens[idx+2:idx+req_toks])
+ current_idx = idx + req_toks
+ elif net_length == 0:
+ req_toks = 5
+ if len(tokens[idx:]) < req_toks:
+ _trunc_error(net_length, req_toks, len(tokens[idx:]))
+ return static_routes
+ net_address = "0.0.0.0"
+ gateway = ".".join(tokens[idx+1:idx+req_toks])
+ current_idx = idx + req_toks
+ else:
+ LOG.error('Parsed invalid net length "%s". Verify DHCP '
+ 'rfc3442-classless-static-routes value.', net_length)
+ return static_routes
+
+ static_routes.append(("%s/%s" % (net_address, net_length), gateway))
+
+ return static_routes
+
# vi: ts=4 expandtab
diff --git a/cloudinit/net/tests/test_dhcp.py b/cloudinit/net/tests/test_dhcp.py
index 5139024..91f503c 100644
--- a/cloudinit/net/tests/test_dhcp.py
+++ b/cloudinit/net/tests/test_dhcp.py
@@ -8,7 +8,8 @@ from textwrap import dedent
import cloudinit.net as net
from cloudinit.net.dhcp import (
InvalidDHCPLeaseFileError, maybe_perform_dhcp_discovery,
- parse_dhcp_lease_file, dhcp_discovery, networkd_load_leases)
+ parse_dhcp_lease_file, dhcp_discovery, networkd_load_leases,
+ parse_static_routes)
from cloudinit.util import ensure_file, write_file
from cloudinit.tests.helpers import (
CiTestCase, HttprettyTestCase, mock, populate_dir, wrap_and_call)
@@ -64,6 +65,123 @@ class TestParseDHCPLeasesFile(CiTestCase):
self.assertItemsEqual(expected, parse_dhcp_lease_file(lease_file))
+class TestDHCPRFC3442(CiTestCase):
+
+ def test_parse_lease_finds_rfc3442_classless_static_routes(self):
+ """parse_dhcp_lease_file returns rfc3442-classless-static-routes."""
+ lease_file = self.tmp_path('leases')
+ content = dedent("""
+ lease {
+ interface "wlp3s0";
+ fixed-address 192.168.2.74;
+ option subnet-mask 255.255.255.0;
+ option routers 192.168.2.1;
+ option rfc3442-classless-static-routes 0,130,56,240,1;
+ renew 4 2017/07/27 18:02:30;
+ expire 5 2017/07/28 07:08:15;
+ }
+ """)
+ expected = [
+ {'interface': 'wlp3s0', 'fixed-address': '192.168.2.74',
+ 'subnet-mask': '255.255.255.0', 'routers': '192.168.2.1',
+ 'rfc3442-classless-static-routes': '0,130,56,240,1',
+ 'renew': '4 2017/07/27 18:02:30',
+ 'expire': '5 2017/07/28 07:08:15'}]
+ write_file(lease_file, content)
+ self.assertItemsEqual(expected, parse_dhcp_lease_file(lease_file))
+
+ @mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network')
+ @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
+ def test_obtain_lease_parses_static_routes(self, m_maybe, m_ipv4):
+ """EphemeralDHPCv4 parses rfc3442 routes for EphemeralIPv4Network"""
+ lease = [
+ {'interface': 'wlp3s0', 'fixed-address': '192.168.2.74',
+ 'subnet-mask': '255.255.255.0', 'routers': '192.168.2.1',
+ 'rfc3442-classless-static-routes': '0,130,56,240,1',
+ 'renew': '4 2017/07/27 18:02:30',
+ 'expire': '5 2017/07/28 07:08:15'}]
+ m_maybe.return_value = lease
+ eph = net.dhcp.EphemeralDHCPv4()
+ eph.obtain_lease()
+ expected_kwargs = {
+ 'interface': 'wlp3s0',
+ 'ip': '192.168.2.74',
+ 'prefix_or_mask': '255.255.255.0',
+ 'broadcast': '192.168.2.255',
+ 'static_routes': [('0.0.0.0/0', '130.56.240.1')],
+ 'router': '192.168.2.1'}
+ m_ipv4.assert_called_with(**expected_kwargs)
+
+
+class TestDHCPParseStaticRoutes(CiTestCase):
+
+ with_logs = True
+
+ def parse_static_routes_empty_string(self):
+ self.assertEqual([], parse_static_routes(""))
+
+ def test_parse_static_routes_invalid_input_returns_empty_list(self):
+ rfc3442 = "32,169,254,169,254,130,56,248"
+ self.assertEqual([], parse_static_routes(rfc3442))
+
+ def test_parse_static_routes_bogus_width_returns_empty_list(self):
+ rfc3442 = "33,169,254,169,254,130,56,248"
+ self.assertEqual([], parse_static_routes(rfc3442))
+
+ def test_parse_static_routes_single_ip(self):
+ rfc3442 = "32,169,254,169,254,130,56,248,255"
+ self.assertEqual([('169.254.169.254/32', '130.56.248.255')],
+ parse_static_routes(rfc3442))
+
+ def test_parse_static_routes_single_ip_handles_trailing_semicolon(self):
+ rfc3442 = "32,169,254,169,254,130,56,248,255;"
+ self.assertEqual([('169.254.169.254/32', '130.56.248.255')],
+ parse_static_routes(rfc3442))
+
+ def test_parse_static_routes_default_route(self):
+ rfc3442 = "0,130,56,240,1"
+ self.assertEqual([('0.0.0.0/0', '130.56.240.1')],
+ parse_static_routes(rfc3442))
+
+ def test_parse_static_routes_class_c_b_a(self):
+ class_c = "24,192,168,74,192,168,0,4"
+ class_b = "16,172,16,172,16,0,4"
+ class_a = "8,10,10,0,0,4"
+ rfc3442 = ",".join([class_c, class_b, class_a])
+ self.assertEqual(sorted([
+ ("192.168.74.0/24", "192.168.0.4"),
+ ("172.16.0.0/16", "172.16.0.4"),
+ ("10.0.0.0/8", "10.0.0.4")
+ ]), sorted(parse_static_routes(rfc3442)))
+
+ def test_parse_static_routes_logs_error_truncated(self):
+ bad_rfc3442 = {
+ "class_c": "24,169,254,169,10",
+ "class_b": "16,172,16,10",
+ "class_a": "8,10,10",
+ "gateway": "0,0",
+ "netlen": "33,0",
+ }
+ for rfc3442 in bad_rfc3442.values():
+ self.assertEqual([], parse_static_routes(rfc3442))
+
+ logs = self.logs.getvalue()
+ self.assertEqual(len(bad_rfc3442.keys()), len(logs.splitlines()))
+
+ def test_parse_static_routes_returns_valid_routes_until_parse_err(self):
+ class_c = "24,192,168,74,192,168,0,4"
+ class_b = "16,172,16,172,16,0,4"
+ class_a_error = "8,10,10,0,0"
+ rfc3442 = ",".join([class_c, class_b, class_a_error])
+ self.assertEqual(sorted([
+ ("192.168.74.0/24", "192.168.0.4"),
+ ("172.16.0.0/16", "172.16.0.4"),
+ ]), sorted(parse_static_routes(rfc3442)))
+
+ logs = self.logs.getvalue()
+ self.assertIn(rfc3442, logs.splitlines()[0])
+
+
class TestDHCPDiscoveryClean(CiTestCase):
with_logs = True
diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py
index 6d2affe..d393e6a 100644
--- a/cloudinit/net/tests/test_init.py
+++ b/cloudinit/net/tests/test_init.py
@@ -549,6 +549,45 @@ class TestEphemeralIPV4Network(CiTestCase):
self.assertEqual(expected_setup_calls, m_subp.call_args_list)
m_subp.assert_has_calls(expected_teardown_calls)
+ def test_ephemeral_ipv4_network_with_rfc3442_static_routes(self, m_subp):
+ params = {
+ 'interface': 'eth0', 'ip': '192.168.2.2',
+ 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255',
+ 'static_routes': [('169.254.169.254/32', '192.168.2.1'),
+ ('0.0.0.0/0', '192.168.2.1')],
+ 'router': '192.168.2.1'}
+ expected_setup_calls = [
+ mock.call(
+ ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
+ 'broadcast', '192.168.2.255', 'dev', 'eth0'],
+ capture=True, update_env={'LANG': 'C'}),
+ mock.call(
+ ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
+ capture=True),
+ mock.call(
+ ['ip', '-4', 'route', 'add', '169.254.169.254/32',
+ 'via', '192.168.2.1', 'dev', 'eth0'], capture=True),
+ mock.call(
+ ['ip', '-4', 'route', 'add', '0.0.0.0/0',
+ 'via', '192.168.2.1', 'dev', 'eth0'], capture=True)]
+ expected_teardown_calls = [
+ mock.call(
+ ['ip', '-4', 'route', 'del', '0.0.0.0/0',
+ 'via', '192.168.2.1', 'dev', 'eth0'], capture=True),
+ mock.call(
+ ['ip', '-4', 'route', 'del', '169.254.169.254/32',
+ 'via', '192.168.2.1', 'dev', 'eth0'], capture=True),
+ mock.call(
+ ['ip', '-family', 'inet', 'link', 'set', 'dev',
+ 'eth0', 'down'], capture=True),
+ mock.call(
+ ['ip', '-family', 'inet', 'addr', 'del',
+ '192.168.2.2/24', 'dev', 'eth0'], capture=True)
+ ]
+ with net.EphemeralIPv4Network(**params):
+ self.assertEqual(expected_setup_calls, m_subp.call_args_list)
+ m_subp.assert_has_calls(expected_setup_calls + expected_teardown_calls)
+
class TestApplyNetworkCfgNames(CiTestCase):
V1_CONFIG = textwrap.dedent("""\
diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
index f27ef21..2de2aea 100644
--- a/tests/unittests/test_datasource/test_azure.py
+++ b/tests/unittests/test_datasource/test_azure.py
@@ -1807,7 +1807,8 @@ class TestAzureDataSourcePreprovisioning(CiTestCase):
self.assertEqual(m_dhcp.call_count, 2)
m_net.assert_any_call(
broadcast='192.168.2.255', interface='eth9', ip='192.168.2.9',
- prefix_or_mask='255.255.255.0', router='192.168.2.1')
+ prefix_or_mask='255.255.255.0', router='192.168.2.1',
+ static_routes=None)
self.assertEqual(m_net.call_count, 2)
def test__reprovision_calls__poll_imds(self, fake_resp,
@@ -1845,7 +1846,8 @@ class TestAzureDataSourcePreprovisioning(CiTestCase):
self.assertEqual(m_dhcp.call_count, 2)
m_net.assert_any_call(
broadcast='192.168.2.255', interface='eth9', ip='192.168.2.9',
- prefix_or_mask='255.255.255.0', router='192.168.2.1')
+ prefix_or_mask='255.255.255.0', router='192.168.2.1',
+ static_routes=None)
self.assertEqual(m_net.call_count, 2)
diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py
index 20d59bf..1ec8e00 100644
--- a/tests/unittests/test_datasource/test_ec2.py
+++ b/tests/unittests/test_datasource/test_ec2.py
@@ -538,7 +538,8 @@ class TestEc2(test_helpers.HttprettyTestCase):
m_dhcp.assert_called_once_with('eth9')
m_net.assert_called_once_with(
broadcast='192.168.2.255', interface='eth9', ip='192.168.2.9',
- prefix_or_mask='255.255.255.0', router='192.168.2.1')
+ prefix_or_mask='255.255.255.0', router='192.168.2.1',
+ static_routes=None)
self.assertIn('Crawl of metadata service took', self.logs.getvalue())
--
cgit v0.10.2

View File

@ -1,57 +0,0 @@
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index 8c18aa1..7575223 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -435,6 +435,14 @@ class TestDsIdentify(DsIdentifyBase):
"""Open Telecom identification."""
self._test_ds_found('OpenStack-OpenTelekom')
+ def test_openstack_asset_tag_nova(self):
+ """OpenStack identification via asset tag OpenStack Nova."""
+ self._test_ds_found('OpenStack-AssetTag-Nova')
+
+ def test_openstack_asset_tag_copute(self):
+ """OpenStack identification via asset tag OpenStack Compute."""
+ self._test_ds_found('OpenStack-AssetTag-Compute')
+
def test_openstack_on_non_intel_is_maybe(self):
"""On non-Intel, openstack without dmi info is maybe.
@@ -759,6 +767,18 @@ VALID_CFG = {
'files': {P_CHASSIS_ASSET_TAG: 'OpenTelekomCloud\n'},
'mocks': [MOCK_VIRT_IS_XEN],
},
+ 'OpenStack-AssetTag-Nova': {
+ # VMware vSphere can't modify product-name, LP: #1669875
+ 'ds': 'OpenStack',
+ 'files': {P_CHASSIS_ASSET_TAG: 'OpenStack Nova\n'},
+ 'mocks': [MOCK_VIRT_IS_XEN],
+ },
+ 'OpenStack-AssetTag-Compute': {
+ # VMware vSphere can't modify product-name, LP: #1669875
+ 'ds': 'OpenStack',
+ 'files': {P_CHASSIS_ASSET_TAG: 'OpenStack Compute\n'},
+ 'mocks': [MOCK_VIRT_IS_XEN],
+ },
'OVF-seed': {
'ds': 'OVF',
'files': {
diff --git a/tools/ds-identify b/tools/ds-identify
index 6518901..e16708f 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -979,6 +979,14 @@ dscheck_OpenStack() {
return ${DS_FOUND}
fi
+ # LP: #1669875 : allow identification of OpenStack by asset tag
+ if dmi_chassis_asset_tag_matches "$nova"; then
+ return ${DS_FOUND}
+ fi
+ if dmi_chassis_asset_tag_matches "$compute"; then
+ return ${DS_FOUND}
+ fi
+
# LP: #1715241 : arch other than intel are not identified properly.
case "$DI_UNAME_MACHINE" in
i?86|x86_64) :;;

View File

@ -1,3 +1,45 @@
-------------------------------------------------------------------
Thu Sep 26 12:15:50 UTC 2019 - Robert Schweikert <rjschwei@suse.com>
- Update to cloud-init 19.2 (bsc#1099358)
+ Remove, included upstream
- cloud-init-detect-nova.diff
- cloud-init-add-static-routes.diff
+ net: add rfc3442 (classless static routes) to EphemeralDHCP
(LP: #1821102)
+ templates/ntp.conf.debian.tmpl: fix missing newline for pools
(LP: #1836598)
+ Support netplan renderer in Arch Linux [Conrad Hoffmann]
+ Fix typo in publicly viewable documentation. [David Medberry]
+ Add a cdrom size checker for OVF ds to ds-identify
[Pengpeng Sun] (LP: #1806701)
+ VMWare: Trigger the post customization script via cc_scripts module.
[Xiaofeng Wang] (LP: #1833192)
+ Cloud-init analyze module: Added ability to analyze boot events.
[Sam Gilson]
+ Update debian eni network configuration location, retain Ubuntu setting
[Janos Lenart]
+ net: skip bond interfaces in get_interfaces
[Stanislav Makar] (LP: #1812857)
+ Fix a couple of issues raised by a coverity scan
+ Add missing dsname for Hetzner Cloud datasource [Markus Schade]
+ doc: indicate that netplan is default in Ubuntu now
+ azure: add region and AZ properties from imds compute location metadata
+ sysconfig: support more bonding options [Penghui Liao]
+ cloud-init-generator: use libexec path to ds-identify on redhat systems
(LP: #1833264)
+ tools/build-on-freebsd: update to python3 [Gonéri Le Bouder]
+ Allow identification of OpenStack by Asset Tag
[Mark T. Voelker] (LP: #1669875)
+ Fix spelling error making 'an Ubuntu' consistent. [Brian Murray]
+ run-container: centos: comment out the repo mirrorlist [Paride Legovini]
+ netplan: update netplan key mappings for gratuitous-arp (LP: #1827238)
+ freebsd: fix the name of cloudcfg VARIANT [Gonéri Le Bouder]
+ freebsd: ability to grow root file system [Gonéri Le Bouder]
+ freebsd: NoCloud data source support [Gonéri Le Bouder] (LP: #1645824)
+ Azure: Return static fallback address as if failed to find endpoint
[Jason Zions (MSFT)]
-------------------------------------------------------------------
Tue Sep 24 19:50:33 UTC 2019 - Robert Schweikert <rjschwei@suse.com>
@ -58,7 +100,7 @@ Tue Jun 11 12:37:16 UTC 2019 - Dominique Leuenberger <dimstar@opensuse.org>
-------------------------------------------------------------------
Fri May 31 12:42:49 UTC 2019 - Robert Schweikert <rjschwei@suse.com>
- Update to version 19.1 (bsc#1136440)
- Update to version 19.1 (bsc#1136440, bsc#1129124)
+ Remove, included upstream
- fix-default-systemd-unit-dir.patch
- cloud-init-sysconf-ethsetup.patch
@ -135,6 +177,7 @@ Fri May 31 12:42:49 UTC 2019 - Robert Schweikert <rjschwei@suse.com>
+ Enable encrypted_data_bag_secret support for Chef
[Eric Williams] (LP: #1817082)
+ azure: Filter list of ssh keys pulled from fabric [Jason Zions (MSFT)]
CVE-2019-0816
+ doc: update merging doc with fixes and some additional details/examples
+ tests: integration test failure summary to use traceback if empty error
+ This is to fix https://bugs.launchpad.net/cloud-init/+bug/1812676

View File

@ -18,7 +18,7 @@
%global configver 0.7
Name: cloud-init
Version: 19.1
Version: 19.2
Release: 0
License: GPL-3.0 and AGPL-3.0
Summary: Cloud node initialization tool
@ -27,7 +27,6 @@ Group: System/Management
Source0: %{name}-%{version}.tar.gz
Source1: rsyslog-cloud-init.cfg
# FIXME
# python2 disables SIGPIPE, causing broken pipe errors in shell scripts (bsc#903449)
Patch20: cloud-init-python2-sigpipe.patch
@ -42,15 +41,11 @@ Patch41: cloud-init-static-net.patch
Patch42: cloud-init-ostack-metadat-dencode.patch
# FIXME (lp#1812117)
Patch43: cloud-init-write-routes.patch
# FIXME (lp#1817368)
# FIXME (lp#1817368) expected in 19.3
Patch47: cloud-init-trigger-udev.patch
# FIXME (lp#1669875) patch by mvoelker@launchpad
Patch48: cloud-init-detect-nova.diff
# FIXME (lp#1821102)
Patch49: cloud-init-add-static-routes.diff
# FIXME (lp#1843634)
# FIXME (lp#1843634) expected in 19.3
Patch50: cloud-init-noresolv-merge-no-dns-data.diff
# FIXME
# FIXME expected in 19.3
Patch51: cloud-init-after-wicked.patch
BuildRequires: fdupes
@ -195,8 +190,6 @@ Documentation and examples for cloud-init tools
%patch42
%patch43
%patch47
%patch48 -p1
%patch49 -p1
%patch50 -p1
%patch51 -p1