Merge ~bitfehler/cloud-init:bitfehler/load_seed into cloud-init:master

Proposed by Conrad Hoffmann
Status: Needs review
Proposed branch: ~bitfehler/cloud-init:bitfehler/load_seed
Merge into: cloud-init:master
Diff against target: 272 lines (+115/-58)
5 files modified
cloudinit/sources/DataSourceCloudStack.py (+9/-4)
cloudinit/sources/DataSourceNoCloud.py (+18/-8)
cloudinit/sources/DataSourceOVF.py (+3/-2)
cloudinit/util.py (+23/-40)
tests/unittests/test_util.py (+62/-4)
Reviewer Review Type Date Requested Status
Scott Moser Needs Information
Server Team CI bot continuous-integration Approve
Ryan Harper Needs Information
Review via email: mp+369814@code.launchpad.net

Commit message

Support network-config in nocloud(-net) data source

This proposal adds a new function `load_seed` that can be used as a replacement for `read_seeded` and `read_optional_seed`, but has support for additional files (network-config, vendor-data).

The nocloud(-net) data source is updated to make use of it, adding support for network-config in user-supplied seeds. This addresses the following bugs:

https://bugs.launchpad.net/cloud-init/+bug/1809180
https://bugs.launchpad.net/cloud-init/+bug/1809277

The OVH and CloudStack datasources are also updated to use the new function, but without changing the data source semantics. Finally, as all previous callers have been updated, the old functions `read_seeded` and `read_optional_seed` are removed.

To post a comment you must log in.
Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

Hi,

I previously wrote a message to the mailing list, but without any response so far, so I figured I'd write some more code and try this way. Happy about any suggestions for improvements or guidance for other approaches.

Some notes right away:
 - The "xenial" tox env does not work for me, even on clean master, is this a known issue?
 - I thought it would be nice to make a holistic change (i.e. changing all callers to the new function), but in fact I do not have access to a test setup for the OVH or CloudStack data sources. How is this usually handled? Is it preferable to not touch any data sources you can not test? Or are there means for this to be tested before it lands in a release?

Thanks a bunch,
Conrad

Revision history for this message
Ryan Harper (raharper) wrote :

Thanks for sending in the merge proposal.

On Mon, Jul 8, 2019 at 7:55 AM Conrad Hoffmann <email address hidden> wrote:

> Hi,
>
> I previously wrote a message to the mailing list, but without any response
> so far, so I figured I'd write some more code and try this way. Happy about
> any suggestions for improvements or guidance for other approaches.
>
> Some notes right away:
> - The "xenial" tox env does not work for me, even on clean master, is
> this a known issue?
>

That's not know, so if you want to file a bug with your output/failure etc
we can take a look.

> - I thought it would be nice to make a holistic change (i.e. changing all
> callers to the new function), but in fact I do not have access to a test
> setup for the OVH or CloudStack data sources. How is this usually handled?
> Is it preferable to not touch any data sources you can not test? Or are
> there means for this to be tested before it lands in a release?
>

We typically do functional behavior changes only in the development release
and then disable them in older releases to prevent behavioral changes.
Depending on the change, we may or maynot test directly on those platforms;
most platform changes are driven from platform owners. That doesn't
preclude such a change so we'd take it case-by-case.

>
> Thanks a bunch,
> Conrad
> --
>
> 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.
>
> _______________________________________________
> Mailing list: https://launchpad.net/~cloud-init-dev
> Post to : <email address hidden>
> Unsubscribe : https://launchpad.net/~cloud-init-dev
> More help : https://help.launchpad.net/ListHelp
>

Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

> Thanks for sending in the merge proposal.
>
>
>
> On Mon, Jul 8, 2019 at 7:55 AM Conrad Hoffmann <email address hidden> wrote:
>
> > Hi,
> >
> > I previously wrote a message to the mailing list, but without any response
> > so far, so I figured I'd write some more code and try this way. Happy about
> > any suggestions for improvements or guidance for other approaches.
> >
> > Some notes right away:
> > - The "xenial" tox env does not work for me, even on clean master, is
> > this a known issue?
> >
>
> That's not know, so if you want to file a bug with your output/failure etc
> we can take a look.

Will do.

> > - I thought it would be nice to make a holistic change (i.e. changing all
> > callers to the new function), but in fact I do not have access to a test
> > setup for the OVH or CloudStack data sources. How is this usually handled?
> > Is it preferable to not touch any data sources you can not test? Or are
> > there means for this to be tested before it lands in a release?
> >
>
> We typically do functional behavior changes only in the development release
> and then disable them in older releases to prevent behavioral changes.
> Depending on the change, we may or maynot test directly on those platforms;
> most platform changes are driven from platform owners. That doesn't
> preclude such a change so we'd take it case-by-case.

What would that mean for this PR? Should I leave it as is? Or should I change it so that only the nocloud data source uses the new function? I don't mind this waiting for the next release, I do understand it is a slight change in behavior.

Thanks again,
Conrad

> > Thanks a bunch,
> > Conrad
> > --
> >
> > 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.
> >
> > _______________________________________________
> > Mailing list: https://launchpad.net/~cloud-init-dev
> > Post to : <email address hidden>
> > Unsubscribe : https://launchpad.net/~cloud-init-dev
> > More help : https://help.launchpad.net/ListHelp
> >

Revision history for this message
Ryan Harper (raharper) wrote :

> What would that mean for this PR? Should I leave it as is? Or should I
> change it so that only the nocloud data source uses the new function?
> I don't mind this waiting for the next release, I do understand it is
> a slight change in behavior.

In case you missed, I had some comments you can see below in the diff output
about the unittests. Let's address those first.

As for this branch; it appears to me to be a super-set of capabilities
more than a change in existing behavior. That is, I expect the datasource
given the same inputs to produce the same behavior;

We are likely to take the updated behavior into master, and include that in
the Ubuntu E release; it could be disabled by default on previous releases
but allowing users to opt-in to the new behavior.

Revision history for this message
Conrad Hoffmann (bitfehler) :
Revision history for this message
Ryan Harper (raharper) wrote :

Thanks for updating the unittests. I've done some additional review and added some inline comments in the diff below. Please take a look.

review: Needs Information
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:90186f8113d73acc437f2d690ec1d43a5d6a9b96
https://jenkins.ubuntu.com/server/job/cloud-init-ci/777/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/777/rebuild

review: Approve (continuous-integration)
Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

Hi,

sorry it took so long, I think I addressed all your comments in the latest commit.

Cheers,
Conrad

Revision history for this message
Ryan Harper (raharper) wrote :

Thanks for the update. I've one more question in-line; The new unittests look great.

review: Needs Information
8ba83bb... by Conrad Hoffmann <email address hidden>

Return empty dict on invalid yaml in load_seed()

Also add a test for this to emphasize that this is the expected
behavior.

Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

Good catch, I fixed that and also added a test for this for the future.

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:8ba83bb8912a8d1614275551be45a7e1fa91173c
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1107/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1107//rebuild

review: Approve (continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote :

I'm not sure that I understand the intent here.

The subject line says:
 Support network-config in nocloud(-net) data source

But nocloud-net cannot ever really provide network-data.
It simply runs too late. No "network" datasources can apply network config as before they have the opportunity to read information the network is already up.

At this point in cluod-init none of the renderers are idempotent. They have to be written before networking is brought up by the OS.

So what we *can* accomplish now (and maybe what this does?) is:

a.) datasourceNoCloud could read networking files from a 'seedfrom'. It already can read network-config from /var/lib/cloud/nocloud/network-config

b.) dataSourceNoCloud could use ephemeral networking to attempt 'seedfrom' of http/https.

But what we can't (I don't think) do:

c.) dataSourceNoCloud-net support reading network-config *at all*.

Last thing... In your commit message, if you believe that you fix those bugs,
please use:
 LP: #XXXXX
 LP: #YYYYY

then all the tools and such will read that and handle closing/fixing bugs.

review: Needs Information
Revision history for this message
Ryan Harper (raharper) wrote :

Looking at the first bug:

https://bugs.launchpad.net/cloud-init/+bug/1809180

I understand it to:
  1) boot NoCloud (fallback networking is utilized)
  2) at cloud-init init stage, NoCloud-Net is loaded, which now supports reading URLs
     including network-config files from URL.
  3) during init stage the .network_config property on NoCloudNet is provided via loading the seed and reading the URLs
  4) cloud-init init stage will render an updated network-config to the system.

This leaves a system with a fallback network config up (including dhclient) but the on-disk network-config is from the URL. On subsequent boots, it will utilize the network-config from the seed URL.

This appears to resolve the request; though it's not completely clear without more feedback from the submitter w.r.t the use-case "boot an image in a new environment without running cloud-init a second time".

A more complete fix would be to modify NoCloud to use EphemeralDHCP to bring up networking if a seed prefix included URLs (as Scott suggests in (b)).

The second bug suggests exactly (b).

I don't think it would be too much more effort to pull in the EphemeralDHCP bits.

Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

Thank you for the comments. I indeed somewhat misjudged the relation of the nocloud and nocloud-net data sources.

To clarify, my main objective was a) as mentioned by Scott and also the hope to maybe unify some of the approaches to reading the seed (like getting rid of read_optional_seed and potentially also pathprefix2dict in a follow-up).

However, I also think b) would be valuable. I am happy to look at adding ephemeral DHCP, but maybe in a different MR?

I now understand that this certainly doesn't fix https://bugs.launchpad.net/cloud-init/+bug/1809277. I am unsure about https://bugs.launchpad.net/cloud-init/+bug/1809180, but I read it like if the nocloud-net does render the "new" network config even though the network is already up then that's fine. I will try to get clarification from the submitter.

Would you be ok with merging this if I update the description and commit messages to reflect the narrower scope?

Revision history for this message
Scott Moser (smoser) wrote :

"if the nocloud-net does render the "new" network config even though the network is already up then that's fine."

Its *not* fine. network datasources should not render network information at this point. Doing so will only confuse things and create a system that "maybe works". We cannot really ensure that it will work, and we're not going to support if it didn't.

So just make it simpler, and only read network config in the local.

Revision history for this message
Scott Moser (smoser) wrote :

(and just so i dont sound rude.... thank you for attempts to clean things up. for sure, there have been many iterative ways of doing things over time and you're seeing that here).

Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

No worries, I understand your point. I guess I am just surprised that that bug report is in state triaged then. It should probably be closed as won't fix with a link to this discussion maybe?

I'll update this MR accordingly.

Revision history for this message
Scott Moser (smoser) wrote :

In the end, it doesn't really matter if its nocloud-net or nocloud.
If nocloud supports reading 'seedfrom' via the ephemeral network, then you get the exact same thing you would have gotten if nocloud-net could actually work like that.

Revision history for this message
Scott Moser (smoser) wrote :

So lets do this...
stage 1) support seedfrom of local paths to get the network config
stage 2) use ephemeral networking to nocloud-net if seedfrom is http or https.

Sound reasonable?

64ce489... by Conrad Hoffmann <email address hidden>

Support seeded network-config in local mode only

Revision history for this message
Conrad Hoffmann (bitfehler) wrote :

I added another commit which I think should achieve what you described as stage 1), while not allowing a seed network-config in nocloud-net. Let me know what you think.

Unmerged commits

64ce489... by Conrad Hoffmann <email address hidden>

Support seeded network-config in local mode only

8ba83bb... by Conrad Hoffmann <email address hidden>

Return empty dict on invalid yaml in load_seed()

Also add a test for this to emphasize that this is the expected
behavior.

efb12b3... by Conrad Hoffmann

More kwargs and better exception handling

90186f8... by Conrad Hoffmann

Improve tests for load_seed

Make test name more descriptive (again) and provide test for URL
handling capabilities.

5a07ceb... by Conrad Hoffmann

Remove read_seeded and read_optional_seed

They are no longer used, mostly replaced by calls to `load_seed`.

475b563... by Conrad Hoffmann

Port several data sources to use load_seed

Use `load_seed` instead of either `read_seeded` or `read_optional_seed`
for the following data sources: CloudStack, NoCloud, OVF. This removes
all usage of both of these functions.

For the nocloud(-net) data source, this enables support for reading a
network-config from a user-supplied seed. This addresses the following
bugs:

https://bugs.launchpad.net/cloud-init/+bug/1809180
https://bugs.launchpad.net/cloud-init/+bug/1809277

For the other data sources, semantics were not changed, though this
change should facilitate e.g. supporting a seed network-config.

48fd9c8... by Conrad Hoffmann

Add load_seed function to facilitate seed loading

It can handle both local files and remote URLS, and otherwise has an
interface similar to pathprefix2dict, supporting required and optional
files (e.g. to support network-config without requiring it). It parses
meta-data and network-config to YAML, others must be handled by the
caller.

Intended to be a replacement for `read_seeded` and `read_optional_seed`.
Includes some basic tests.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py
index f185dc7..4bc40ae 100644
--- a/cloudinit/sources/DataSourceCloudStack.py
+++ b/cloudinit/sources/DataSourceCloudStack.py
@@ -110,12 +110,17 @@ class DataSourceCloudStack(sources.DataSource):
110 return self.cfg110 return self.cfg
111111
112 def _get_data(self):112 def _get_data(self):
113 seed_ret = {}113 try:
114 if util.read_optional_seed(seed_ret, base=(self.seed_dir + "/")):114 # Using `required` wrapped in try because we want both or none
115 self.userdata_raw = seed_ret['user-data']115 seed = util.load_seed(self.seed_dir,
116 self.metadata = seed_ret['meta-data']116 required=['meta-data', 'user-data'])
117 self.userdata_raw = seed['user-data']
118 self.metadata = seed['meta-data']
117 LOG.debug("Using seeded cloudstack data from: %s", self.seed_dir)119 LOG.debug("Using seeded cloudstack data from: %s", self.seed_dir)
118 return True120 return True
121 except Exception:
122 util.logexc(LOG, 'Failed to read seeded data from %s',
123 self.seed_dir)
119 try:124 try:
120 if not self.wait_for_metadata_service():125 if not self.wait_for_metadata_service():
121 return False126 return False
diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py
index 474773d..2b158fe 100644
--- a/cloudinit/sources/DataSourceNoCloud.py
+++ b/cloudinit/sources/DataSourceNoCloud.py
@@ -163,15 +163,23 @@ class DataSourceNoCloud(sources.DataSource):
163 LOG.debug("Seed from %s not supported by %s", seedfrom, self)163 LOG.debug("Seed from %s not supported by %s", seedfrom, self)
164 return False164 return False
165165
166 # This could throw errors, but the user told us to do it166 # This could fail, but the user told us to do it,
167 # so if errors are raised, let them raise167 # so if it does, abort
168 (md_seed, ud) = util.read_seeded(seedfrom, timeout=None)168 try:
169 kwargs = {'required': ['user-data', 'meta-data'],
170 'optional': []}
171 if self.dsmode == sources.DSMODE_LOCAL:
172 kwargs['optional'] = ['network-config']
173 seed = util.load_seed(seedfrom, timeout=None, **kwargs)
174 except Exception:
175 util.logexc(LOG, 'Failed to read seeded data from %s',
176 seedfrom)
177 return False
178
169 LOG.debug("Using seeded cache data from %s", seedfrom)179 LOG.debug("Using seeded cache data from %s", seedfrom)
170180
171 # Values in the command line override those from the seed181 # Values in the command line override those from the seed
172 mydata['meta-data'] = util.mergemanydict([mydata['meta-data'],182 mydata = _merge_new_seed(mydata, seed)
173 md_seed])
174 mydata['user-data'] = ud
175 found.append(seedfrom)183 found.append(seedfrom)
176184
177 # Now that we have exhausted any other places merge in the defaults185 # Now that we have exhausted any other places merge in the defaults
@@ -357,8 +365,10 @@ def _merge_new_seed(cur, seeded):
357 ret['meta-data'] = util.mergemanydict([cur['meta-data'], newmd])365 ret['meta-data'] = util.mergemanydict([cur['meta-data'], newmd])
358366
359 if seeded.get('network-config'):367 if seeded.get('network-config'):
360 ret['network-config'] = _maybe_remove_top_network(368 newnc = seeded['network-config']
361 util.load_yaml(seeded.get('network-config')))369 if not isinstance(newnc, dict):
370 newnc = util.load_yaml(seeded['network-config'])
371 ret['network-config'] = _maybe_remove_top_network(newnc)
362372
363 if 'user-data' in seeded:373 if 'user-data' in seeded:
364 ret['user-data'] = seeded['user-data']374 ret['user-data'] = seeded['user-data']
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index e7794aa..7ddd063 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -286,10 +286,11 @@ class DataSourceOVF(sources.DataSource):
286 seedfrom, self)286 seedfrom, self)
287 return False287 return False
288288
289 (md_seed, ud) = util.read_seeded(seedfrom, timeout=None)289 seed = util.load_seed(seedfrom, required=['meta-data'],
290 timeout=None)
290 LOG.debug("Using seeded cache data from %s", seedfrom)291 LOG.debug("Using seeded cache data from %s", seedfrom)
291292
292 md = util.mergemanydict([md, md_seed])293 md = util.mergemanydict([md, seed.get('meta-data', {})])
293 found.append(seedfrom)294 found.append(seedfrom)
294295
295 # Now that we have exhausted any other places merge in the defaults296 # Now that we have exhausted any other places merge in the defaults
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 0d338ca..6f11dec 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -893,22 +893,6 @@ def runparts(dirp, skip_no_exist=True, exe_prefix=None):
893 % (len(failed), len(attempted)))893 % (len(failed), len(attempted)))
894894
895895
896# read_optional_seed
897# returns boolean indicating success or failure (presense of files)
898# if files are present, populates 'fill' dictionary with 'user-data' and
899# 'meta-data' entries
900def read_optional_seed(fill, base="", ext="", timeout=5):
901 try:
902 (md, ud) = read_seeded(base, ext, timeout)
903 fill['user-data'] = ud
904 fill['meta-data'] = md
905 return True
906 except url_helper.UrlError as e:
907 if e.code == url_helper.NOT_FOUND:
908 return False
909 raise
910
911
912def fetch_ssl_details(paths=None):896def fetch_ssl_details(paths=None):
913 ssl_details = {}897 ssl_details = {}
914 # Lookup in these locations for ssl key/cert files898 # Lookup in these locations for ssl key/cert files
@@ -975,34 +959,33 @@ def load_yaml(blob, default=None, allowed=(dict,)):
975 return loaded959 return loaded
976960
977961
978def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0):962def load_seed(base='', required=None, optional=None, timeout=5):
963 result = {}
964 if required is None:
965 required = []
966 if optional is None:
967 optional = []
979 if base.startswith("/"):968 if base.startswith("/"):
980 base = "file://%s" % base969 base = "file://%s" % base
981970
982 # default retries for file is 0. for network is 10971 for item in required + optional:
983 if base.startswith("file://"):972 try:
984 retries = file_retries973 url = url_helper.combine_url(base, item)
974 resp = url_helper.read_file_or_url(url, timeout)
975 if resp.ok():
976 if item in ['meta-data', 'network-config']:
977 result[item] = load_yaml(decode_binary(resp.contents),
978 default={})
979 else:
980 result[item] = resp.contents
981 except url_helper.UrlError as e:
982 LOG.debug('Failed to read %s: %s', url, e)
983 if item in optional and e.code == url_helper.NOT_FOUND:
984 pass
985 else:
986 raise e
985987
986 if base.find("%s") >= 0:988 return result
987 ud_url = base % ("user-data" + ext)
988 md_url = base % ("meta-data" + ext)
989 else:
990 ud_url = "%s%s%s" % (base, "user-data", ext)
991 md_url = "%s%s%s" % (base, "meta-data", ext)
992
993 md_resp = url_helper.read_file_or_url(md_url, timeout, retries,
994 file_retries)
995 md = None
996 if md_resp.ok():
997 md = load_yaml(decode_binary(md_resp.contents), default={})
998
999 ud_resp = url_helper.read_file_or_url(ud_url, timeout, retries,
1000 file_retries)
1001 ud = None
1002 if ud_resp.ok():
1003 ud = ud_resp.contents
1004
1005 return (md, ud)
1006989
1007990
1008def read_conf_d(confd):991def read_conf_d(confd):
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 0e71db8..f5d2c63 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -9,6 +9,7 @@ import shutil
9import stat9import stat
10import tempfile10import tempfile
1111
12import httpretty
12import json13import json
13import six14import six
14import sys15import sys
@@ -724,9 +725,9 @@ class TestMessageFromString(helpers.TestCase):
724 self.assertNotIn('\x00', roundtripped)725 self.assertNotIn('\x00', roundtripped)
725726
726727
727class TestReadSeeded(helpers.TestCase):728class TestLoadSeed(helpers.HttprettyTestCase):
728 def setUp(self):729 def setUp(self):
729 super(TestReadSeeded, self).setUp()730 super(TestLoadSeed, self).setUp()
730 self.tmp = tempfile.mkdtemp()731 self.tmp = tempfile.mkdtemp()
731 self.addCleanup(shutil.rmtree, self.tmp)732 self.addCleanup(shutil.rmtree, self.tmp)
732733
@@ -734,12 +735,69 @@ class TestReadSeeded(helpers.TestCase):
734 ud = b"userdatablob"735 ud = b"userdatablob"
735 helpers.populate_dir(736 helpers.populate_dir(
736 self.tmp, {'meta-data': "key1: val1", 'user-data': ud})737 self.tmp, {'meta-data': "key1: val1", 'user-data': ud})
737 sdir = self.tmp + os.path.sep738 seed = util.load_seed(self.tmp, required=['meta-data', 'user-data'])
738 (found_md, found_ud) = util.read_seeded(sdir)739 found_md = seed.get('meta-data', {})
740 found_ud = seed.get('user-data', '')
739741
740 self.assertEqual(found_md, {'key1': 'val1'})742 self.assertEqual(found_md, {'key1': 'val1'})
741 self.assertEqual(found_ud, ud)743 self.assertEqual(found_ud, ud)
742744
745 def test_non_yaml_returns_empty_dict(self):
746 blob = b"randomblob"
747 helpers.populate_dir(self.tmp, {'meta-data': blob})
748 seed = util.load_seed(self.tmp, required=['meta-data'])
749 found_md = seed.get('meta-data')
750
751 self.assertEqual(found_md, {})
752
753 def test_handles_urls(self):
754 ud = b"userdatablob"
755 base = 'http://foo.bar/datasource'
756 httpretty.register_uri(
757 httpretty.GET,
758 base + '/meta-data',
759 body='foo: bar')
760 httpretty.register_uri(
761 httpretty.GET,
762 base + '/user-data',
763 body=ud)
764 seed = util.load_seed(base, required=['meta-data', 'user-data'])
765 found_md = seed.get('meta-data', {})
766 found_ud = seed.get('user-data', '')
767
768 self.assertEqual(found_md, {'foo': 'bar'})
769 self.assertEqual(found_ud, ud)
770
771 def test_ignores_optional(self):
772 ud = b"userdatablob"
773 helpers.populate_dir(
774 self.tmp, {'meta-data': 'key1: val1', 'user-data': ud})
775 seed = util.load_seed(
776 self.tmp, ['meta-data', 'user-data'], ['network-config'])
777 found_md = seed.get('meta-data', {})
778 found_ud = seed.get('user-data', '')
779
780 self.assertEqual(found_md, {'key1': 'val1'})
781 self.assertEqual(found_ud, ud)
782
783 def test_loads_optional(self):
784 ud = b"userdatablob"
785 helpers.populate_dir(
786 self.tmp, {
787 'meta-data': 'key1: val1',
788 'user-data': ud,
789 'network-config': 'key: val'
790 })
791 seed = util.load_seed(
792 self.tmp, ['meta-data', 'user-data'], ['network-config'])
793 found_md = seed.get('meta-data', {})
794 found_ud = seed.get('user-data', '')
795 found_nc = seed.get('network-config', {})
796
797 self.assertEqual(found_md, {'key1': 'val1'})
798 self.assertEqual(found_ud, ud)
799 self.assertEqual(found_nc, {'key': 'val'})
800
743801
744class TestSubp(helpers.CiTestCase):802class TestSubp(helpers.CiTestCase):
745 with_logs = True803 with_logs = True

Subscribers

People subscribed via source and target branches