Openstack: Vendor data cleanup

For now, this vendor data handling is just added to openstack.
However, in an effort to allow sanely handling of multi-part vendor-data
that is namespaced, we add openstack.convert_vendordata_json .

That basically takes whatever was loaded from vendordata and takes
the 'cloud-init' key if it is a dict.  This way the author can
namespace cloud-init, basically telling it to ignore everything else.
This commit is contained in:
Scott Moser 2014-09-10 21:17:40 -04:00
parent 95fb96e921
commit 7148fe7552
4 changed files with 72 additions and 13 deletions

View File

@ -126,12 +126,13 @@ class DataSourceConfigDrive(openstack.SourceMixin, sources.DataSource):
self.version = results['version']
self.files.update(results.get('files', {}))
# If there is no vendordata, set vd to an empty dict instead of None
vd = results.get('vendordata', {})
# if vendordata includes 'cloud-init', then read that explicitly
# for cloud-init (for namespacing).
if 'cloud-init' in vd:
self.vendordata_raw = vd['cloud-init']
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

View File

@ -140,13 +140,13 @@ class DataSourceOpenStack(openstack.SourceMixin, sources.DataSource):
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

View File

@ -459,3 +459,28 @@ class MetadataReader(BaseReader):
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))

View File

@ -19,6 +19,7 @@
import copy
import json
import re
import unittest
from StringIO import StringIO
@ -256,7 +257,8 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
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):
@ -314,3 +316,34 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
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'])