Merge lp:~hazmat/pyjuju/rapi-annotation into lp:~hazmat/pyjuju/rapi-rollup
- rapi-annotation
- Merge into rapi-rollup
Status: | Merged |
---|---|
Merged at revision: | 623 |
Proposed branch: | lp:~hazmat/pyjuju/rapi-annotation |
Merge into: | lp:~hazmat/pyjuju/rapi-rollup |
Diff against target: |
63 lines (+34/-1) 2 files modified
juju/rapi/delta.py (+1/-1) juju/rapi/transport/tests/test_ws.py (+33/-0) |
To merge this branch: | bzr merge lp:~hazmat/pyjuju/rapi-annotation |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Kapil Thangavelu | Pending | ||
Review via email: mp+140358@code.launchpad.net |
Commit message
Description of the change
annotation api for gui and ls
Allow for annotating domain objects with 3rd party metadata for integration
purposes.
Kapil Thangavelu (hazmat) wrote : | # |
Gary Poster (gary) wrote : | # |
Hi Kapil. This will be great to have, thank you.
All my comments are questions/thoughts. Discard if they don't make
sense to you.
I'd like to spend more time reading annotations.py and the
test_annotations.py but I ran out of time. If you haven't landed this
by the time I get more free time, I'll read that some more and see if I
have any more comments.
Gary
https:/
File juju/rapi/
https:/
juju/rapi/
Would be nice to specify what data is (dict AIUI?)
Should keys always be strings? If so, should that be documented? If
not, specifying expected key types might still be nice.
I'm guessing that the dict is merged with the existing data, so this is
also the change annotation API. I wish that were a bit less surprising
in the name. I notice that you use "set" as the verb on the
AnnotationManager. I like that a lot better, FWIW (set_annotation, or,
per discussion below, set_annotations). "set" conveys the semantics
shown here, where "add" does not.
Generally, for all of these, the fact that the API is singular confuses
me. An API for add_annotation I would expect to be
add_annotation(
map). I would call this API add_annotations
change_
applies to get_annotation => get_annotations and remove_annotation =>
remove_annotations.
https:/
juju/rapi/
by entity, I'm guessing this is name, as with add_annotation. Might as
well clarify it in both doc strings (or neither, if it really should be
understood?)
https:/
File juju/rapi/delta.py (right):
https:/
juju/rapi/
Isn't this inner loop on units potentially problematic at large scale?
I guess we can't jump to the unit somehow without iterating? I'd wonder
if we could change the inner (unexposed) APIs to make this kind of
iteration unnecessary.
https:/
File juju/state/
https:/
juju/state/
typo: cumulative
https:/
juju/state/
of change, as such the
run-on: ...volume of change. As such, the...
https:/
juju/state/
typo: solely
Gary Poster (gary) wrote : | # |
Hi Kapil. I got some time to review annotation.py, with a few comments,
at least one of which I suspect is a bit important (the isdigit).
Thanks
Gary
https:/
File juju/state/
https:/
juju/state/
Might be nice to have a docstring that clarified that context was a
string or an integer. And that returning None indicates no match,
maybe?
https:/
juju/state/
isinstance(context, int):
I suspect you want to reverse those conditions. Ints don't have an
"isdigit" method.
Ideally, this would suggest a test as well.
https:/
juju/state/
maybe clarify in docstring that this is the inverse of _get_key?
https:/
juju/state/
how to delete key
Is this an XXX? It sounds like "how to delete key" is an answered
issue, and I don't understand what the point of the other unicode
comment is, so it could either be expanded or removed.
https:/
juju/state/
Oh! So, this is just a big dict of all annotations, which we load and
dump altogether, right? Huh. I guess this is your point in the module
docstring: this is OK for our use case of annotating services, but
otherwise is potentially problematic in the general case for scaling.
https:/
juju/state/
self._verify_
So...if context is None or an empty string we just use that as the key,
which will return an empty dict. I don't really see the point, but I
don't see a problem either.
https:/
juju/state/
I can see a couple of ways to make this a bit more efficient, but
there's probably not much point. The kinds of things I have in mind:
valid_keys could be a set to begin with. You could just define waste as
set(store) - valid_keys and eliminate an intermediate data structure
(used_keys). Probably not worth it. If you like it, take it, and
otherwise ignore it.
https:/
juju/state/
self)
We are always making one...interesting. I guess you are thinking of it
like __iter__. Why didn't you just call this method __iter__, in fact?
https:/
juju/state/
added.. in the span
"s-a"? service A?
...
Kapil Thangavelu (hazmat) wrote : | # |
On 2012/12/18 14:42:58, gary.poster wrote:
> Hi Kapil. This will be great to have, thank you.
> All my comments are questions/thoughts. Discard if they don't make
sense to
> you.
> I'd like to spend more time reading annotations.py and the
test_annotations.py
> but I ran out of time. If you haven't landed this by the time I get
more free
> time, I'll read that some more and see if I have any more comments.
> Gary
> https:/
> File juju/rapi/
https:/
> juju/rapi/
> Would be nice to specify what data is (dict AIUI?)
> Should keys always be strings? If so, should that be documented? If
not,
> specifying expected key types might still be nice.
at the moments its free form, reasonably keys should always be strings.
i'll add some enforcement of that (in annotation manager). we might end
up restricting to known keys (ls & gui) but i prefer to key it open for
exploration for now. there is enforcement that data is a dict at the
annotation manager level.
> I'm guessing that the dict is merged with the existing data, so this
is also the
> change annotation API. I wish that were a bit less surprising in the
name. I
> notice that you use "set" as the verb on the AnnotationManager. I
like that a
> lot better, FWIW (set_annotation, or, per discussion below,
set_annotations).
> "set" conveys the semantics shown here, where "add" does not.
naming is hard :-)
that's interesting, i changed the name at the exposed api/rapi level
because i had a different i went with add because its clearly
cumulative.. while set might be taken for an equality/total value.
from our irc discussion, i'll go with update_annotations. its a little
ambigious that you update an annotation to create it, but in practice i
think it should be okay.
> Generally, for all of these, the fact that the API is singular
confuses me. An
> API for add_annotation I would expect to be add_annotation(
name, value)
> or change_
i eschewed single value forms to avoid round trips. i originally had a
notion of entity, namespace, map but i realized its just adding
complexity when simplicity would serve. our annotations aren't private
to the creator ala zope.annotation, we have cross annotation usage so a
shared space serves nicely, and makes the consumption a bit simpler as
well.
> I would call this API
> add_annotations
This
> "let's use plurals" comment also applies to get_annotation =>
get_annotations
> and remove_annotation => remove_annotations.
plurals +1
https:/
> juju/rapi/
> by entity, I'm guessing this is name, as with add_annotation. Might
as well
> clarify it in both doc strings (or neither, if it really should be
understood?)
sounds good re doc string w/ entity def.
> https:/
> File juju/rapi/delta.py (righ...
Kapil Thangavelu (hazmat) wrote : | # |
On 2012/12/18 16:43:15, gary.poster wrote:
> Hi Kapil. I got some time to review annotation.py, with a few
comments, at
> least one of which I suspect is a bit important (the isdigit).
> Thanks
> Gary
> https:/
> File juju/state/
https:/
> juju/state/
> Might be nice to have a docstring that clarified that context was a
string or an
> integer. And that returning None indicates no match, maybe?
sounds reasonable.
https:/
> juju/state/
isinstance(context, int):
> I suspect you want to reverse those conditions. Ints don't have an
"isdigit"
> method.
> Ideally, this would suggest a test as well.
nice catch, thanks!
https:/
> juju/state/
> maybe clarify in docstring that this is the inverse of _get_key?
sounds good.
https:/
> juju/state/
ext, how to
> delete key
> Is this an XXX? It sounds like "how to delete key" is an answered
issue, and I
> don't understand what the point of the other unicode comment is, so it
could
> either be expanded or removed.
yeah.. some of this was written science fiction style, and filled in
later, that how to delete key comment should get yanked. the unicode
comment was referencing a concern i had about being able to ensure the c
json encoder for encode/decode speed but looking through
json/(encoder/
https:/
> juju/state/
> Oh! So, this is just a big dict of all annotations, which we load and
dump
> altogether, right? Huh. I guess this is your point in the module
docstring:
> this is OK for our use case of annotating services, but otherwise is
potentially
> problematic in the general case for scaling.
yeah.. the upper bound in zk is roughly 1mb for the node data,
compressed that gets us to roughly 20k entities with annotations which
is fine. if need be its fairly easy to use a consistent hashing function
on the context/keyspace to partition annotations across multiple node...
there are bigger fish to fry i think though. fwiw here's a sample script
i used for a sanity check (and come up with 20k number) using random
data for the annotations, but constant key set.
http://
https:/
> juju/state/
> self._verify_
> So...if context is None or an empty string we just use that as the
key, which
> will return an empty dict. I don't really see the point, but I don't
see a
> problem either.
...
Benjamin Saller (bcsaller) wrote : | # |
Quick review, this looks pretty good and like you said, given the
trajectory of the code base I think this is basically enough for now.
I'd like your thoughts on moving how /annotations are stored (below),
and if its worth observing annotation changes apart from the normal
delta, but I'm basically happy to move forward with this now.
https:/
File juju/rapi/
https:/
juju/rapi/
On 2012/12/18 14:42:58, gary.poster wrote:
> Would be nice to specify what data is (dict AIUI?)
> Should keys always be strings? If so, should that be documented? If
not,
> specifying expected key types might still be nice.
> I'm guessing that the dict is merged with the existing data, so this
is also the
> change annotation API. I wish that were a bit less surprising in the
name. I
> notice that you use "set" as the verb on the AnnotationManager. I
like that a
> lot better, FWIW (set_annotation, or, per discussion below,
set_annotations).
> "set" conveys the semantics shown here, where "add" does not.
> Generally, for all of these, the fact that the API is singular
confuses me. An
> API for add_annotation I would expect to be add_annotation(
name, value)
> or change_
> add_annotations
This
> "let's use plurals" comment also applies to get_annotation =>
get_annotations
> and remove_annotation => remove_annotations.
I agree with this comment. Context here is a key entry point into the
API and should be outlined in more detail.
https:/
File juju/state/
https:/
juju/state/
Will we ever want to annotate relations directly? Juju-Gui's positioning
cases don't depend on this now, but its easy to imaging recording a path
for a manually sculpted relation line. Just something to keep in mind.
https:/
juju/state/
annotation"
An assertion error seems a little harsh here. Client side things haven't
been aggressively typechecked so its possible to pass something that
json can pull out as a dict.
You already have InvalidAnnotati
specific error that can be caught.
https:/
juju/state/
On 2012/12/18 16:43:15, gary.poster wrote:
> Oh! So, this is just a big dict of all annotations, which we load and
dump
> altogether, right? Huh. I guess this is your point in the module
docstring:
> this is OK for our use case of annotating services, but otherwise is
potentially
> problematic in the general case for scaling.
The way the .stream stuff is hooked up I'm not sure we can/should couple
th...
Kapil Thangavelu (hazmat) wrote : | # |
On 2012/12/19 14:44:36, benjamin.saller wrote:
> Quick review, this looks pretty good and like you said, given the
trajectory of
> the code base I think this is basically enough for now. I'd like your
thoughts
> on moving how /annotations are stored (below), and if its worth
observing
> annotation changes apart from the normal delta, but I'm basically
happy to move
> forward with this now.
> https:/
> File juju/rapi/
https:/
> juju/rapi/
> On 2012/12/18 14:42:58, gary.poster wrote:
> > Would be nice to specify what data is (dict AIUI?)
> >
> > Should keys always be strings? If so, should that be documented?
If not,
> > specifying expected key types might still be nice.
> >
> > I'm guessing that the dict is merged with the existing data, so this
is also
> the
> > change annotation API. I wish that were a bit less surprising in the
name. I
> > notice that you use "set" as the verb on the AnnotationManager. I
like that a
> > lot better, FWIW (set_annotation, or, per discussion below,
set_annotations).
> > "set" conveys the semantics shown here, where "add" does not.
> >
> > Generally, for all of these, the fact that the API is singular
confuses me.
> An
> > API for add_annotation I would expect to be add_annotation(
name,
> value)
> > or change_
> > add_annotations
map). This
> > "let's use plurals" comment also applies to get_annotation =>
get_annotations
> > and remove_annotation => remove_annotations.
> I agree with this comment. Context here is a key entry point into the
API and
> should be outlined in more detail.
> https:/
> File juju/state/
https:/
> juju/state/
> Will we ever want to annotate relations directly? Juju-Gui's
positioning cases
> don't depend on this now, but its easy to imaging recording a path for
a
> manually sculpted relation line. Just something to keep in mind.
easy enough to add when we need it, till then yagni.
https:/
> juju/state/
> annotation"
> An assertion error seems a little harsh here. Client side things
haven't been
> aggressively typechecked so its possible to pass something that json
can pull
> out as a dict.
> You already have InvalidAnnotati
specific error
> that can be caught.
switched to stateerror w/ msg
https:/
> juju/state/
> On 2012/12/18 16:43:15, gary.poster wrote:
> > Oh! So, this is just a big dict of all annotations, which we load
and dump
> > altogether, right? Huh. I guess this is your po...
Kapil Thangavelu (hazmat) wrote : | # |
Please take a look.
Gary Poster (gary) wrote : | # |
Kapil Thangavelu (hazmat) wrote : | # |
Please take a look.
Preview Diff
1 | === modified file 'juju/rapi/delta.py' |
2 | --- juju/rapi/delta.py 2013-01-10 15:38:31 +0000 |
3 | +++ juju/rapi/delta.py 2013-01-18 16:59:22 +0000 |
4 | @@ -59,7 +59,7 @@ |
5 | try: |
6 | current = (yield self.context.status())['result'] |
7 | self._annotate( |
8 | - current, (yield self.annotation_stream.next())) |
9 | + current, (yield self.annotations.get())) |
10 | yield self.annotations.gc() |
11 | except Exception, e: |
12 | # The delta pump must go on. |
13 | |
14 | === modified file 'juju/rapi/transport/tests/test_ws.py' |
15 | --- juju/rapi/transport/tests/test_ws.py 2012-10-04 15:58:43 +0000 |
16 | +++ juju/rapi/transport/tests/test_ws.py 2013-01-18 16:59:22 +0000 |
17 | @@ -139,6 +139,38 @@ |
18 | return super(DeltaSocketTest, self).tearDown() |
19 | |
20 | @inlineCallbacks |
21 | + def test_annotations_persist_in_delta(self): |
22 | + yield self.mock_store_charms(["precise/mysql"]) |
23 | + self.mocker.replay() |
24 | + yield self.context.deploy("precise/mysql") |
25 | + yield self.context.update_annotations( |
26 | + "mysql", {'gui.x': 21, 'gui.y': 64}) |
27 | + yield self.stream_manager.pump() |
28 | + yield self.stream_manager.pump() |
29 | + |
30 | + d = self.transport.watch_kv('op', 'delta') |
31 | + self.ws.connectionMade() |
32 | + yield d |
33 | + delta = self.transport.stream[-1] |
34 | + self.assertEqual( |
35 | + delta, |
36 | + {u'op': u'delta', |
37 | + u'result': [ |
38 | + [u'service', |
39 | + u'add', |
40 | + {u'annotations': {u'gui.x': 21, u'gui.y': 64}, |
41 | + u'charm': u'cs:precise/mysql-1', |
42 | + u'id': u'mysql'}], |
43 | + [u'machine', u'add', {u'id': 0, u'instance-id': u'pending'}], |
44 | + [u'unit', |
45 | + u'add', |
46 | + {u'agent-state': u'pending', |
47 | + u'id': u'mysql/0', |
48 | + u'machine': 0, |
49 | + u'public-address': None}]]} |
50 | + ) |
51 | + |
52 | + @inlineCallbacks |
53 | def test_delta_stream(self): |
54 | yield self.mock_store_charms(["precise/wordpress", "precise/mysql"]) |
55 | self.mocker.replay() |
56 | @@ -150,6 +182,7 @@ |
57 | # Modify state and send events out. |
58 | yield self.context.deploy("precise/mysql") |
59 | yield self.context.deploy("wordpress") |
60 | + |
61 | yield self.stream_manager.pump() |
62 | |
63 | delta = self.transport.stream[-1] |
Reviewers: mp+140358_ code.launchpad. net,
Message:
Please take a look.
Description:
annotation api for gui and ls
Allow for annotating domain objects with 3rd party metadata for
integration
purposes.
https:/ /code.launchpad .net/~hazmat/ juju/rapi- annotation/ +merge/ 140358
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/6936063/
Affected files: context. py tests/test_ context. py tests/test_ delta.py annotation. py errors. py relation. py tests/test_ annotation. py tests/test_ topology. py topology. py
A [revision details]
M juju/rapi/
M juju/rapi/delta.py
M juju/rapi/
M juju/rapi/
A juju/state/
M juju/state/
M juju/state/
A juju/state/
M juju/state/
M juju/state/