Code review comment for lp:~frankban/juju-quickstart/old-style-bundles-regression

Revision history for this message
Francesco Banconi (frankban) wrote :

Please take a look.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py
File quickstart/charmstore.py (right):

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode30
quickstart/charmstore.py:30: class NotFoundError(Exception):
On 2015/03/10 01:18:32, rharding wrote:
> can this just use the netutils NotFoundError?

It can. But I didn't implement it lije that on purpose.
My idea is that having the charmstore raise a charmstore.NotFoundError
is part of the contract. Instead, exposing its internal dependency on
netutils.urlread is not. This is why we basically mask the underlying
exception.
With this implementation, we discourage people to write something like:

try:
    charmstore.get(...)
except netutils.NotFoundError: # This currently does not work.
    ...

The code above would establish a connection between the charmstore and
the netutils code, which is only an implementation detail. If, for
instance in the future we decide to replace the simplistic code in
netutils with something like requests or similar, the current API
doesn't have to change, i.e. the charmstore would still raise a
charmstore.NotFoundError.
In essence, clients using the charmstore API doesn't have to know (or
import) netutils, and vice versa.

I considered the module namespace to be good enough to distinguish
between netutils.NotFoundError and charmstore.NotFoundError.

That is the reasoning behind this implementation, and I agree it can
seem a repetition, but it's separation of concerns in my idea. Of course
feel free to disagree with the above.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode34
quickstart/charmstore.py:34: def get(path):
On 2015/03/10 01:18:32, rharding wrote:
> are these internal? Should they be _get prefixed or anything as
internal use
> methods?

The idea is that this is public API. A client can use this function when
no higher level calls are available.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode45
quickstart/charmstore.py:45: url = settings.CHARMSTORE_API +
path.lstrip('/')
On 2015/03/10 01:18:32, rharding wrote:
> can you confirm that the settings will allow overriding the api
endpoint via env
> var? Is that documented, maybe in the hacking doc?

Overriding the charmstore API URL is not supported currently. Do we need
to support that? If so, I'll create a card.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode51
quickstart/charmstore.py:51: raise NotFoundError(msg)
On 2015/03/10 01:18:32, rharding wrote:
> Ok, so this is intentional to tell which kind of "NotFoundError"
you've got by
> if it's a netutils vs a charmstore.py one? Should we name them
different or just
> use the traceback?

Not sure if I understand the question about using the traceback. See
above for the goal of having two separate exception types.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode64
quickstart/charmstore.py:64: For instance, to retrieve the hash of a
charm reference, use the following:
On 2015/03/10 01:18:32, rharding wrote:
> here you mention a charm reference but this is particular to bundles.
Should
> this be bundle reference?

Why is this specific to bundles? The code here works with charms as
well. Am I missing something?

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode68
quickstart/charmstore.py:68: Raise a NotFoundError the an entity with
the given reference cannot be
On 2015/03/10 01:44:34, bac wrote:
> typo: the an entity

Done.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode78
quickstart/charmstore.py:78: def resolve(name, series=None):
On 2015/03/10 01:18:32, rharding wrote:
> what about specifying the version? The main concern is that if it
doesn't exist
> that the failure is consistent or clear to the user.

The goal of resolve is to retrieve the last revision of an entity. If we
already have it, I am not sure about why a client would call this
function. Could you expand on the failure handling part of your
question? Right now, if the entity does not exist, a NotFoundError is
raised.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode116
quickstart/charmstore.py:116: def get_legacy_bundle_data(reference):
On 2015/03/10 01:18:32, rharding wrote:
> do we ever get the legacy bundle though now? I thought we only got the
updated
> bundle and then turned it into legacy format by nesting it inside
another level?

We need to, and I'll try to explain why.
Quickstart bundles support works like this:
- if a new-style bundle is provided (mediawiki-single or u/foo/bar) then
we never retrieve the legacy bundle data, and when sending the bundle to
the GUI server we wrap the decoded YAML with an arbitrary top level
name.
- if an old-style syntax is used (bundle:mediawiki/single) then we have
two possible cases:
   1) the new bundle is named mediawiki-single (in the case multiple
bundle names were included in the basket)
   or 2) the new bundle is named just mediawiki.
   - quickstart tries case 1) first: if it succeeds, there is no need to
get the legacy data, and when sending the bundle to the GUI server we
wrap the decoded YAML with an arbitrary top level name.
   - if case 1) returns a 404, we also try case 2), and this is when this
function is used, because we need to check that a "single" name is
included in the legacy YAML, so that bundle:mediawiki/single works but
bundle:mediawiki/xyz doesn't. We then flatten the retrieved legacy
bundle and we wrap it again as usual when sending it to the GUI server.

So, the answer is yes, quickstart works only with flat bundle and only
nest it inside another level when sending it, and this is done in all
cases. But in the specific case above the legacy data is still required
for validation. The good thing is that the code handling legacy data and
the flattening logic is very confined in the bundles.py module, and the
resulting bundle object is unaware of multiple bundles or the
basket/bundle name concepts.

https://codereview.appspot.com/215070043/diff/1/quickstart/charmstore.py#newcode134
quickstart/charmstore.py:134: def _retrieve_bundle_data(reference,
path):
On 2015/03/10 01:18:32, rharding wrote:
> get_bundle_data vs _retrieve_bundle_data was a bit unclear to me.
Maybe we can
> get the word 'parse' into the function name to help clarify that one
fetches
> while the other actually parses?

Done.

https://codereview.appspot.com/215070043/diff/1/quickstart/models/bundles.py
File quickstart/models/bundles.py (right):

https://codereview.appspot.com/215070043/diff/1/quickstart/models/bundles.py#newcode228
quickstart/models/bundles.py:228: data =
charmstore.get_legacy_bundle_data(reference)
On 2015/03/10 01:18:32, rharding wrote:
> I was expecting this to use the same 'get_bundle_data but with the
different
> reference using only the basket vs getting the orig.yaml file using
the
> get_legacy_bundle_data. Can you clarify this for me please?

As mentioned, this is done because we need to validate the provided
name. Using just get_bundle_data would work, but paradoxically would
work in too many cases: since "bundle:foo/bar" is translated to just
"foo", we would have bundle:foo/* as a valid input, e.g.
"juju-quickstart bundle:foo/exterminate".

https://codereview.appspot.com/215070043/diff/1/quickstart/models/bundles.py#newcode400
quickstart/models/bundles.py:400: def _open_yaml(content):
On 2015/03/10 01:18:32, rharding wrote:
> should this be shared with the yaml parsing code in the charmstore
methods? e.g.
> a utils.py or the like around yaml management?

Done.

https://codereview.appspot.com/215070043/diff/1/quickstart/models/bundles.py#newcode412
quickstart/models/bundles.py:412: def _ensure_is_dict(data):
On 2015/03/10 01:18:32, rharding wrote:
> same here.

This is only used here actually.

https://codereview.appspot.com/215070043/diff/1/quickstart/tests/models/test_bundles.py
File quickstart/tests/models/test_bundles.py (right):

https://codereview.appspot.com/215070043/diff/1/quickstart/tests/models/test_bundles.py#newcode110
quickstart/tests/models/test_bundles.py:110: # XXX frankban 2015-03-09:
remove this check once we get rid of the
On 2015/03/10 01:18:32, rharding wrote:
> maybe we should tag these in a way? I guess the comment is consistent
with the
> world 'charmworld' in it to serve as a way to grep out all of this
that needs
> cleanup down the road.

Yes indeed.

https://codereview.appspot.com/215070043/

« Back to merge proposal