cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #06390
[Merge] ~bitfehler/cloud-init:bitfehler/load_seed into cloud-init:master
Conrad Hoffmann has proposed merging ~bitfehler/cloud-init:bitfehler/load_seed into cloud-init:master.
Requested reviews:
cloud-init commiters (cloud-init-dev)
For more details, see:
https://code.launchpad.net/~bitfehler/cloud-init/+git/cloud-init/+merge/369814
--
Your team cloud-init commiters is requested to review the proposed merge of ~bitfehler/cloud-init:bitfehler/load_seed into cloud-init:master.
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py
index f185dc7..3605076 100644
--- a/cloudinit/sources/DataSourceCloudStack.py
+++ b/cloudinit/sources/DataSourceCloudStack.py
@@ -110,12 +110,15 @@ class DataSourceCloudStack(sources.DataSource):
return self.cfg
def _get_data(self):
- seed_ret = {}
- if util.read_optional_seed(seed_ret, base=(self.seed_dir + "/")):
- self.userdata_raw = seed_ret['user-data']
- self.metadata = seed_ret['meta-data']
+ try:
+ # Using `required` wrapped in try because we want both or none
+ seed = util.load_seed(self.seed_dir, ['meta-data', 'user-data'])
+ self.userdata_raw = seed['user-data']
+ self.metadata = seed['meta-data']
LOG.debug("Using seeded cloudstack data from: %s", self.seed_dir)
return True
+ except Exception:
+ pass
try:
if not self.wait_for_metadata_service():
return False
diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py
index 8a9e5dd..da92875 100644
--- a/cloudinit/sources/DataSourceNoCloud.py
+++ b/cloudinit/sources/DataSourceNoCloud.py
@@ -165,13 +165,11 @@ class DataSourceNoCloud(sources.DataSource):
# This could throw errors, but the user told us to do it
# so if errors are raised, let them raise
- (md_seed, ud) = util.read_seeded(seedfrom, timeout=None)
+ seed = util.load_seed(seedfrom, timeout=None, **pp2d_kwargs)
LOG.debug("Using seeded cache data from %s", seedfrom)
# Values in the command line override those from the seed
- mydata['meta-data'] = util.mergemanydict([mydata['meta-data'],
- md_seed])
- mydata['user-data'] = ud
+ mydata = _merge_new_seed(mydata, seed)
found.append(seedfrom)
# Now that we have exhausted any other places merge in the defaults
@@ -357,8 +355,10 @@ def _merge_new_seed(cur, seeded):
ret['meta-data'] = util.mergemanydict([cur['meta-data'], newmd])
if seeded.get('network-config'):
- ret['network-config'] = _maybe_remove_top_network(
- util.load_yaml(seeded.get('network-config')))
+ newnc = seeded['network-config']
+ if not isinstance(newnc, dict):
+ newnc = util.load_yaml(seeded['network-config'])
+ ret['network-config'] = _maybe_remove_top_network(newnc)
if 'user-data' in seeded:
ret['user-data'] = seeded['user-data']
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index 70e7a5c..dd9b994 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -262,10 +262,10 @@ class DataSourceOVF(sources.DataSource):
seedfrom, self)
return False
- (md_seed, ud) = util.read_seeded(seedfrom, timeout=None)
+ seed = util.load_seed(seedfrom, ['meta-data'], timeout=None)
LOG.debug("Using seeded cache data from %s", seedfrom)
- md = util.mergemanydict([md, md_seed])
+ md = util.mergemanydict([md, seed.get('meta-data', {})])
found.append(seedfrom)
# Now that we have exhausted any other places merge in the defaults
diff --git a/cloudinit/util.py b/cloudinit/util.py
index aa23b3f..43bb0e8 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -892,22 +892,6 @@ def runparts(dirp, skip_no_exist=True, exe_prefix=None):
% (len(failed), len(attempted)))
-# read_optional_seed
-# returns boolean indicating success or failure (presense of files)
-# if files are present, populates 'fill' dictionary with 'user-data' and
-# 'meta-data' entries
-def read_optional_seed(fill, base="", ext="", timeout=5):
- try:
- (md, ud) = read_seeded(base, ext, timeout)
- fill['user-data'] = ud
- fill['meta-data'] = md
- return True
- except url_helper.UrlError as e:
- if e.code == url_helper.NOT_FOUND:
- return False
- raise
-
-
def fetch_ssl_details(paths=None):
ssl_details = {}
# Lookup in these locations for ssl key/cert files
@@ -974,34 +958,31 @@ def load_yaml(blob, default=None, allowed=(dict,)):
return loaded
-def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0):
+def load_seed(base='', required=None, optional=None, timeout=5):
+ result = {}
+ if required is None:
+ required = []
+ if optional is None:
+ optional = []
if base.startswith("/"):
base = "file://%s" % base
- # default retries for file is 0. for network is 10
- if base.startswith("file://"):
- retries = file_retries
+ for item in required + optional:
+ try:
+ url = url_helper.combine_url(base, item)
+ resp = url_helper.read_file_or_url(url, timeout)
+ if resp.ok():
+ if item in ['meta-data', 'network-config']:
+ result[item] = load_yaml(decode_binary(resp.contents))
+ else:
+ result[item] = resp.contents
+ except url_helper.UrlError as e:
+ if item in optional and e.code == url_helper.NOT_FOUND:
+ pass
+ else:
+ raise e
- if base.find("%s") >= 0:
- ud_url = base % ("user-data" + ext)
- md_url = base % ("meta-data" + ext)
- else:
- ud_url = "%s%s%s" % (base, "user-data", ext)
- md_url = "%s%s%s" % (base, "meta-data", ext)
-
- md_resp = url_helper.read_file_or_url(md_url, timeout, retries,
- file_retries)
- md = None
- if md_resp.ok():
- md = load_yaml(decode_binary(md_resp.contents), default={})
-
- ud_resp = url_helper.read_file_or_url(ud_url, timeout, retries,
- file_retries)
- ud = None
- if ud_resp.ok():
- ud = ud_resp.contents
-
- return (md, ud)
+ return result
def read_conf_d(confd):
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 0e71db8..a31031a 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -724,21 +724,52 @@ class TestMessageFromString(helpers.TestCase):
self.assertNotIn('\x00', roundtripped)
-class TestReadSeeded(helpers.TestCase):
+class TestLoadSeed(helpers.TestCase):
def setUp(self):
- super(TestReadSeeded, self).setUp()
+ super(TestLoadSeed, self).setUp()
self.tmp = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, self.tmp)
- def test_unicode_not_messed_up(self):
+ def test_simple_seed(self):
ud = b"userdatablob"
helpers.populate_dir(
self.tmp, {'meta-data': "key1: val1", 'user-data': ud})
- sdir = self.tmp + os.path.sep
- (found_md, found_ud) = util.read_seeded(sdir)
+ seed = util.load_seed(self.tmp, required=['meta-data', 'user-data'])
+ found_md = seed.get('meta-data', {})
+ found_ud = seed.get('user-data', '')
+
+ self.assertEqual(found_md, {'key1': 'val1'})
+ self.assertEqual(found_ud, ud)
+
+ def test_ignores_optional(self):
+ ud = b"userdatablob"
+ helpers.populate_dir(
+ self.tmp, {'meta-data': 'key1: val1', 'user-data': ud})
+ seed = util.load_seed(
+ self.tmp, ['meta-data', 'user-data'], ['network-config'])
+ found_md = seed.get('meta-data', {})
+ found_ud = seed.get('user-data', '')
+
+ self.assertEqual(found_md, {'key1': 'val1'})
+ self.assertEqual(found_ud, ud)
+
+ def test_loads_optional(self):
+ ud = b"userdatablob"
+ helpers.populate_dir(
+ self.tmp, {
+ 'meta-data': 'key1: val1',
+ 'user-data': ud,
+ 'network-config': 'key: val'
+ })
+ seed = util.load_seed(
+ self.tmp, ['meta-data', 'user-data'], ['network-config'])
+ found_md = seed.get('meta-data', {})
+ found_ud = seed.get('user-data', '')
+ found_nc = seed.get('network-config', {})
self.assertEqual(found_md, {'key1': 'val1'})
self.assertEqual(found_ud, ud)
+ self.assertEqual(found_nc, {'key': 'val'})
class TestSubp(helpers.CiTestCase):
Follow ups