diff -Nru cloud-init-0.7.5/debian/changelog cloud-init-0.7.5/debian/changelog --- cloud-init-0.7.5/debian/changelog 2015-09-02 13:58:26.000000000 -0300 +++ cloud-init-0.7.5/debian/changelog 2015-09-10 12:51:25.000000000 -0300 @@ -1,3 +1,11 @@ +cloud-init (0.7.5-0ubuntu1.11) trusty; urgency=medium + + * d/patches/fix-consumption-of-vendor-data.patch: + - Fix consumption of vendor-data in OpenStack to allow namespacing + (LP: #1469260). + + -- Felipe Reyes Thu, 10 Sep 2015 12:50:32 -0300 + cloud-init (0.7.5-0ubuntu1.10) trusty; urgency=medium [ Daniel Watkins ] diff -Nru cloud-init-0.7.5/debian/patches/lp1469260-fix-consumption-of-vendor-data.patch cloud-init-0.7.5/debian/patches/lp1469260-fix-consumption-of-vendor-data.patch --- cloud-init-0.7.5/debian/patches/lp1469260-fix-consumption-of-vendor-data.patch 1969-12-31 21:00:00.000000000 -0300 +++ cloud-init-0.7.5/debian/patches/lp1469260-fix-consumption-of-vendor-data.patch 2015-09-10 12:49:46.000000000 -0300 @@ -0,0 +1,162 @@ +Author: Scott Moser +Bug: https://bugs.launchpad.net/cloud-init/+bug/1469260 +Applied-Upstream: yes +Origin: http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/revision/1013 +Description: OpenStack: fix consumption of vendor-data to allow namespacing + . + Not all vendor data is destined for cloud-init. This sanely reads + the vendor data as a dict, array or a string. + +--- a/cloudinit/sources/DataSourceConfigDrive.py ++++ b/cloudinit/sources/DataSourceConfigDrive.py +@@ -125,7 +125,14 @@ + self.userdata_raw = results.get('userdata') + self.version = results['version'] + self.files.update(results.get('files', {})) +- self.vendordata_raw = results.get('vendordata') ++ vd = results.get('vendordata') ++ self.vendordata_pure = vd ++ try: ++ self.vendordata_raw = openstack.convert_vendordata_json(vd) ++ except ValueError as e: ++ LOG.warn("Invalid content in vendor-data: %s", e) ++ self.vendordata_raw = None ++ + return True + + +--- a/cloudinit/sources/DataSourceOpenStack.py ++++ b/cloudinit/sources/DataSourceOpenStack.py +@@ -143,13 +143,13 @@ + self.version = results['version'] + self.files.update(results.get('files', {})) + +- # if vendordata includes 'cloud-init', then read that explicitly +- # for cloud-init (for namespacing). + vd = results.get('vendordata') +- if isinstance(vd, dict) and 'cloud-init' in vd: +- self.vendordata_raw = vd['cloud-init'] +- else: +- self.vendordata_raw = vd ++ self.vendordata_pure = vd ++ try: ++ self.vendordata_raw = openstack.convert_vendordata_json(vd) ++ except ValueError as e: ++ LOG.warn("Invalid content in vendor-data: %s", e) ++ self.vendordata_raw = None + + return True + +--- a/cloudinit/sources/helpers/openstack.py ++++ b/cloudinit/sources/helpers/openstack.py +@@ -21,6 +21,7 @@ + import abc + import base64 + import copy ++import functools + import os + + from cloudinit import ec2_utils +@@ -196,6 +197,9 @@ + If not a valid location, raise a NonReadable exception. + """ + ++ load_json_anytype = functools.partial( ++ util.load_json, root_types=(dict, basestring, list)) ++ + def datafiles(version): + files = {} + files['metadata'] = ( +@@ -214,7 +218,7 @@ + files['vendordata'] = ( + self._path_join("openstack", version, 'vendor_data.json'), + False, +- util.load_json, ++ load_json_anytype, + ) + return files + +@@ -437,3 +441,28 @@ + return ec2_utils.get_instance_metadata(ssl_details=self.ssl_details, + timeout=self.timeout, + retries=self.retries) ++ ++ ++def convert_vendordata_json(data, recurse=True): ++ """ data: a loaded json *object* (strings, arrays, dicts). ++ return something suitable for cloudinit vendordata_raw. ++ ++ if data is: ++ None: return None ++ string: return string ++ list: return data ++ the list is then processed in UserDataProcessor ++ dict: return convert_vendordata_json(data.get('cloud-init')) ++ """ ++ if not data: ++ return None ++ if isinstance(data, (str, unicode, basestring)): ++ return data ++ if isinstance(data, list): ++ return copy.deepcopy(data) ++ if isinstance(data, dict): ++ if recurse is True: ++ return convert_vendordata_json(data.get('cloud-init'), ++ recurse=False) ++ raise ValueError("vendordata['cloud-init'] cannot be dict") ++ raise ValueError("Unknown data type for vendordata: %s" % type(data)) +--- a/tests/unittests/test_datasource/test_openstack.py ++++ b/tests/unittests/test_datasource/test_openstack.py +@@ -19,6 +19,7 @@ + import copy + import json + import re ++import unittest + + from StringIO import StringIO + +@@ -241,7 +242,8 @@ + self.assertEquals(EC2_META, ds_os.ec2_metadata) + self.assertEquals(USER_DATA, ds_os.userdata_raw) + self.assertEquals(2, len(ds_os.files)) +- self.assertEquals(VENDOR_DATA, ds_os.vendordata_raw) ++ self.assertEquals(VENDOR_DATA, ds_os.vendordata_pure) ++ self.assertEquals(ds_os.vendordata_raw, None) + + @hp.activate + def test_bad_datasource_meta(self): +@@ -299,3 +301,34 @@ + found = ds_os.get_data() + self.assertFalse(found) + self.assertIsNone(ds_os.version) ++ ++ ++class TestVendorDataLoading(unittest.TestCase): ++ def cvj(self, data): ++ return openstack.convert_vendordata_json(data) ++ ++ def test_vd_load_none(self): ++ # non-existant vendor-data should return none ++ self.assertIsNone(self.cvj(None)) ++ ++ def test_vd_load_string(self): ++ self.assertEqual(self.cvj("foobar"), "foobar") ++ ++ def test_vd_load_list(self): ++ data = [{'foo': 'bar'}, 'mystring', list(['another', 'list'])] ++ self.assertEqual(self.cvj(data), data) ++ ++ def test_vd_load_dict_no_ci(self): ++ self.assertEqual(self.cvj({'foo': 'bar'}), None) ++ ++ def test_vd_load_dict_ci_dict(self): ++ self.assertRaises(ValueError, self.cvj, ++ {'foo': 'bar', 'cloud-init': {'x': 1}}) ++ ++ def test_vd_load_dict_ci_string(self): ++ data = {'foo': 'bar', 'cloud-init': 'VENDOR_DATA'} ++ self.assertEqual(self.cvj(data), data['cloud-init']) ++ ++ def test_vd_load_dict_ci_list(self): ++ data = {'foo': 'bar', 'cloud-init': ['VD_1', 'VD_2']} ++ self.assertEqual(self.cvj(data), data['cloud-init']) diff -Nru cloud-init-0.7.5/debian/patches/series cloud-init-0.7.5/debian/patches/series --- cloud-init-0.7.5/debian/patches/series 2015-09-02 13:57:17.000000000 -0300 +++ cloud-init-0.7.5/debian/patches/series 2015-09-10 12:49:46.000000000 -0300 @@ -13,3 +13,4 @@ lp-1470880-fix-gce-az-determination.patch lp-1470890-include-regions-in-dynamic-mirror-discovery.patch lp-1490796-azure-fix-mount_cb-for-symlinks.patch +lp1469260-fix-consumption-of-vendor-data.patch