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

Revision history for this message
Richard Harding (rharding) wrote :

On 2015/03/10 10:20:07, 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.

LGTM with the one update we talked about this morning. Thanks for this
solid branch.

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

« Back to merge proposal