/srv/irclogs.ubuntu.com/2012/12/06/#juju-dev.txt

rogpeppedavecheney: morning06:09
davecheneyrogpeppe: morning !06:10
davecheneyhow's it going06:10
rogpeppenot too bad06:10
davecheneyrogpeppe: here's one for ya! https://codereview.appspot.com/6862050/06:12
davecheneyrogpeppe: look at this http://code.google.com/p/rietveld/issues/detail?id=406#c206:22
rogpeppedavecheney: re the above CL: why not just rename serialisedLogger to logger and lose the interface type?06:40
rogpeppedavecheney: (i was planning to run the race detector on our tests today too actually - nice idea)06:41
davecheneyrogpeppe: yeah, we can do that06:41
davecheneyrogpeppe: yes, i've been running it on the core state/* and worker classes06:42
davecheneywe're pretty good06:42
rogpeppedavecheney: that's a relief to hear06:42
rogpeppedavecheney: although it would be interesting to run some of the tests concurrently.06:43
davecheneyoh boy, don't even think about GOMAXPROCS > 106:43
rogpeppei meant concurrently rather than in parallel, but that too06:43
davecheneyoooooooooooh, you mean all the state tests at once ?06:44
rogpeppedavecheney: well, obviously that wouldn't currently be possible, but yeah, that kind of thing06:48
rogpeppedavecheney: gocheck should allow the equivalent of t.Parallel() (if i remember that name right)06:49
rogpeppehttp://golang.org/pkg/testing/#T.Parallel06:49
rogpeppei really think that gocheck could use some modernisation06:50
rogpeppedavecheney: you've got a review on that gocheck CL06:52
davecheneyrogpeppe: ta muchly06:55
fwereademornings06:55
TheMueMornings from a snowy Oldenburg too06:57
fwereadeTheMue, I forget, did I discuss the meaning of a Dying Machine with you? I'm trying to find someone who can explain in what circumstances a Machine should be able to become so, and how the consequences of that make sense07:23
fwereadeTheMue_, I forget, did I discuss the meaning of a Dying Machine with you? I'm trying to find someone who can explain in what circumstances a Machine should be able to become so, and how the consequences of that make sense07:25
=== TheMue_ is now known as TheMue
fwereadeTheMue, ping07:54
TheMuefwereade: Pong.07:54
fwereadeTheMue, I think you might have missed:07:55
fwereade<fwereade> TheMue, I forget, did I discuss the meaning of a Dying Machine with you? I'm trying to find someone who can explain in what circumstances a Machine should be able to become so, and how the consequences of that make sense07:55
TheMuefwereade: Oh, yes, I missed. Strange.07:55
fwereadeTheMue, because the "obvious" meaning is that the machine should start to shut itself down when it becomes Dying07:56
fwereadeTheMue, but actually, if it has units, it can't do that: it'll be blocked for as long as they exist, which could be forever07:56
fwereadeTheMue, but the machine will from that point on be kinda broken -- eg you won't be able to assign new units to it07:57
fwereadeTheMue, and the Alive=>Dying change is irrevocable07:57
fwereadeTheMue, and it really doesn't seem like a smart idea to ever put machines in that state07:57
TheMuefwereade: So far following, yes.07:58
fwereadeTheMue, can you think of an alternative conception of what should happen? or, if not, do you then agree that a Dying machine is somewhere between meaningless and harmful?07:59
TheMuefwereade: To take a step back, I always had my problems with the idea of setting lifecyle a state to trigger a reaction.08:01
TheMuefwereade: My natural feeling is more vice versa.08:01
fwereadeTheMue, that's interesting, would you expand on how you'd prefer to see it?08:01
TheMuefwereade: I somehow tell a machine to to stop. During this, it sets its state to Daying to represent this. And at the end it sets its state to Dead.08:01
TheMuefwereade: So the lifecycle state is only a representing and informal information for others to see what's going on.08:02
fwereadeTheMue, I thought that was the model we did follow? except with the first bit slightly compressed -- ie that setting something to Dying is precisely how we communicate that it should stop08:02
TheMuefwereade: Yes, and that's what I dislike.08:03
TheMuefwereade: Because it isn't dying, we want it to do so.08:03
TheMuefwereade: And itself can only tell: "Hey, guys, I'm dying."08:04
TheMuefwereade: But that's only a personal preference and I won't start this discussion again. ;)08:04
fwereadeTheMue, if it's annoying for you to go over it again then I'll gladly drop it, but I'm interested in your perspective here08:06
fwereadeTheMue, what do you expect will be watching for the Dying status?08:06
TheMuefwereade: No, it's not annoying. But we have an agreement, so that should be changed.08:07
fwereadeTheMue, ofc it's tedious to discuss this generally, because the various lifecycle entities are much more different than I think we ever imagined :/08:07
TheMuefwereade: Currently I don't know for whom it could be interesting to watch the Dying status, but it could be interesting if I'm iterating and only want those with status Alive.08:08
TheMuefwereade: Yes, exactly.08:08
fwereadeTheMue, I don't *think* that's a sane operation, but I could easily be wrong08:09
fwereadeTheMue, yeah, I'm sure I'm wrong somewhere, just because there are so many possibilities :)08:09
TheMuefwereade: But let's come back to the current way to do so and what you've discovered.08:10
fwereadeTheMue, heh, much of this will be messy, I don't think I've ever tried to express it all at once before, but here goes08:10
fwereadeTheMue, so: the detect-self-Dying=>cleanup-and-set-self-Dead model is very clear when it comes to entities that have agents, ie units and machines08:12
fwereadeTheMue, notwithstanding my belief that it isn't *actually* sane wrt machines08:12
fwereadeTheMue, but in any case it's definitely different to service and relation lifecycle management08:13
fwereadeTheMue, because those entities rely on agents for other entities to manage them08:13
TheMuefwereade: Yep.08:14
fwereadeTheMue, (and in fact units depend on machine agents (or sometimes other unit agents), and machine agents depend on other machine agents (ie those running provisioners)08:14
fwereadeTheMue, so, putting it that way, maybe it's not as different as I thought: ie *every* entity has its lifecycle partly managed by something else08:15
fwereadeTheMue, it's just that some of them don't have their own agents at all, so their lifecycles have to be exclusively managed by other things08:15
fwereadeTheMue, but, nonetheless08:16
fwereadeTheMue, Relation has already lost EnsureDead on the basis that that is not a meaningful change08:16
fwereadeTheMue, actually, it's lost EnsureDying too08:17
fwereadeTheMue, it just has Destroy08:17
fwereadeTheMue, are you familiar with that change and its context?08:17
fwereadeTheMue, (it should also be noted that there's no such thing as a Dead relation -- the possible paths are Alive -> removed and Alive -> Dying -> removed)08:18
TheMuefwereade: Not yet, but I'm simply following what you're saying here and raise a question when I need more background (or at least I think so).08:18
TheMuefwereade: Sounds reasonable.08:19
fwereadeTheMue, the issue is basically that the point at which a relation can be removed is the point at which the last relation unit leaves scope08:20
fwereadeTheMue, we can't enter scope if any of the involved entities are dying08:21
fwereadeTheMue, and in fact no entity will take it on itself to just remove a Dying relation -- if the relation is Dying when the uniter first sees it, it just ignores it08:22
TheMuefwereade: Hmm, that's a bit too short and fast.08:22
TheMuefwereade: Could you please explain it differently.08:22
fwereadeTheMue, I'll try :)08:22
fwereadeTheMue, a relation exists, and we don't want it to any more08:23
fwereadeTheMue, the "easy" answer is "set Dying, let the system handle it"08:23
TheMuefwereade: That's the UI, but how shall the system do it.08:24
fwereadeTheMue, but if there are no units currently participating in that relation, there is no entity with responsibility for that relation's death08:24
fwereadeTheMue, it would ordinarily be the last unit08:24
fwereadeTheMue, to leave scope08:24
fwereadeTheMue, but if none are in scope this isn't sane08:24
fwereadeTheMue, so, in the absence of a CA, just setting Dying is not good enough08:25
TheMuefwereade: Why does the relation exist if there's no unit in scope?08:25
fwereadeTheMue, because someone related two services before any of the services machines were provisioned, for example08:26
fwereadeTheMue, relation scope is how units express their personal participation in a relation08:26
fwereadeTheMue, a scope is meaningless without a relation, but a relation on its own is just an expression of how we would like the units of certain services to communicate08:27
TheMuefwereade: Ah, yes, forgot it.08:27
fwereadeTheMue, so, EnsureDying is useless08:28
fwereadeTheMue, and for similar reasons EnsureDead is useless, except even more so, because by definition a relation cannot become Dead while there is some unit in scope -- ie some unit willing to take responsibility for finally removing it08:29
fwereadeTheMue, so the actual lifecycle management (apart from creation) is managed by some slightly icky transactions in RU.EnterScope, RU.LeaveScope, and R.Destroy08:30
fwereadeTheMue, and nothing therein ever sets the relation to Dead -- once it's safe to make it Dead, it's safe to destroy it entirely08:30
fwereadeTheMue, making sense so far?08:31
TheMuefwereade: Yes, can follow.08:31
fwereadeTheMue, ok, now apply what I have just said to Service08:31
fwereadeTheMue, I *think* that the only sane way to manage service is as above08:32
fwereadeTheMue, ie via careful txn management in S.AddUnit, S.RemoveUnit, and (mooted) s.Destroy08:32
fwereadeTheMue, for service, this renders EnsureDying and EnsureDead meaningless08:33
fwereadeTheMue, and in fact the Dead state is again meaningless for a Service08:33
TheMuefwereade: It feels more natural than fiddling with life states.08:33
fwereadeTheMue, yeah, hopefully so :)08:34
fwereadeTheMue, the trouble is that the life model as we originally designed it does not apply to:08:34
fwereadeTheMue, 1) relations -- no meaningful Dead08:34
fwereadeTheMue, 2) services -- no meaningful Dead08:35
fwereadeTheMue, 3) machines -- no meaningful Dying08:35
fwereadeTheMue, 4) and units -- because Alive/Dying/Dead is (according to niemeyer) not expressive enough to accommodate forced removal08:35
fwereadeTheMue, and my big personal problem is that we still seem to have this idea that lifecycles are agreed, and make sense, and have already been implemented08:36
TheMuefwereade: I don't hear you anymore. *whistling*08:36
fwereadeTheMue, when in fact they aren't, they don't, and they haven't08:36
fwereadeTheMue, haha :)08:37
TheMuefwereade: Somehow you're hitting the nerve. Never thought about it so concentrated.08:37
fwereadeTheMue, if you can see any holes in the above, please poke them, because I'm going to have to muster the emotional energy to bring this up with niemeyer at some point soon, and yu know how it can be -- one missed detail means he dismissed your whole argument08:38
TheMuefwereade: For me the life discussion is difficult. I prefer to collect facts/arguments/etc in a document and discuss that. It's simpler to refer to.08:43
fwereadeTheMue, (ofc I don't mean to say he always does that -- but it is a risk I am loath to assume)08:43
rogpeppefwereade: for me, the big advantage of Dying is that the entity enters a shutdown phase, meaning that other things can't interact with it while it's dying (which might take several transactions)09:08
fwereaderogpeppe, yeah, I know that's what we think it means09:10
fwereaderogpeppe, in practice, leaving aside the niche use case in which we render a machine crippled for an arbitrary length of time, Dying STM not to be a useful state for a machine... or, if it is, it's one we can only enter when the machine has no units09:11
fwereaderogpeppe, but we certainly don't enforce that anywhere09:11
fwereaderogpeppe, I'd be perfectly happy with that restriction, but it's pretty inconsistent with everything else09:12
rogpeppefwereade: the problem is: when can you remove a machine?09:12
rogpeppefwereade: and i guess the answer is: when it has no units assigned09:12
fwereaderogpeppe, when and only when it has no units assigned, I think09:12
rogpeppefwereade: ok, in this case we can consider dying/dead redundant because they're compressed into one transaction ("remove iff no units")09:13
fwereaderogpeppe, I think we still need Dead, so the provisioner can trash the instance and remove the machine09:14
rogpeppefwereade: ok, EnsureDead iff no units09:15
rogpeppefwereade: which presumably the Machine.EnsureDead checks anyway09:15
rogpeppefwereade: ha, it doesn't09:16
rogpeppefwereade: but it should09:16
fwereaderogpeppe, yeah, like just about every other bit f lifecycle that we'v "implemented" :/09:16
rogpeppefwereade: can we check for no units and set to dead all in one tranaction?09:17
fwereaderogpeppe, think so, yeah09:17
rogpeppefwereade: well, actually, given dying and dead, it's not a problem09:18
rogpeppefwereade: we don't need to do that09:18
rogpeppefwereade: but, as you've said, perhaps it doesn't really make sense to tag a machine to die in the future09:19
rogpeppefwereade: a unit could live its entire life on a Dying machine09:19
rogpeppefwereade: which seems kinda cool in a sf kinda way :-)09:19
fwereaderogpeppe, yeah, exactly -- and I'm not even saying that use case never applies09:20
fwereaderogpeppe, just that I'm not sure it should be our primary focus09:20
rogpeppefwereade: i still think that even if we don't leverage all the states, dying and dead is still a useful way to think about removing entities09:21
fwereaderogpeppe, ok, but... Dying is (currently) useless for machines09:22
fwereaderogpeppe, Dead is meaningless for relations and services09:22
rogpeppefwereade: even if for some things, we just use Remove instead of EnsureDead, and for others we don't use Dying at all.09:22
fwereaderogpeppe, and niemeyer wants an extra lifecycley flag for units to accommodate --force09:22
rogpeppefwereade: i'm still not sure about --force and how it should be done. there are quite a few edge cases there that i'm wary of.09:23
fwereaderogpeppe, well, yeah -- IMO the only sane way is with a single transaction, but meh, niemeyer wants a flag so he's probably going to get a flag09:24
rogpeppefwereade: can't it be a flag on the unit rather than an extra lifecycle state that everything needs to deal with?09:24
fwereaderogpeppe, yeah, but IMO that kicks the last leg out from underthe idea that there is anything usefull common about lifecycle handling09:25
rogpeppefwereade: i don't think so. the dying/dead distinction is still useful there09:25
fwereaderogpeppe, the existence of the states as they is, IMO, just fine09:25
fwereaderogpeppe, but in practice no entity follows the model we've kidded ourselves that they all do09:26
fwereaderogpeppe, the only features that STM to apply across the board are:09:26
fwereade  * lifecycle state can only advance09:26
fwereade  * entity lifecycles can sometimes skip states09:26
fwereade  * no agent/entity is responsible for removing itself09:26
rogpeppethat seems fine to me09:27
rogpeppefwereade: it doesn't say that lifecycle state is irrelevant09:27
fwereaderogpeppe, when did I say it was?09:27
fwereaderogpeppe, the states are fine09:27
fwereaderogpeppe, but we're operating under a shared delusion that we've understood the problem09:27
rogpeppefwereade: ah, i thought you were objecting to Dying and Dead09:27
fwereaderogpeppe, no -- just conceits like EnsureDying and EnsureDead09:28
rogpeppefwereade: they're just setting flags. i'd never expected them to be anything other than part of the solution.09:28
fwereaderogpeppe, but just setting a flag is almost always crackful09:29
rogpeppefwereade: yeah, quite possibly. i think maybe they should not be exported09:29
rogpeppefwereade: then each entity gets methods that are appropriate09:29
fwereaderogpeppe, I'm pretty sure they shouldn't even exist -- they're premature abstraction that's just trying to wedge everything into the same model, that doesn't actually ever apply to anything09:30
rogpeppefwereade: such as Remove (for a machine - only works if no units)09:30
fwereaderogpeppe, I think entity.Destroy is sensible09:30
fwereaderogpeppe, to go with the agreed CLI terminology09:30
fwereaderogpeppe, that's what we have for relations anyway09:30
fwereaderogpeppe, and what I *think* we need for services09:30
rogpeppefwereade: i dunno. i think EnsureDying is reasonable for things where the entity *will* take a while to clear up.09:31
fwereaderogpeppe, and how do yu determine that to be the case?09:31
rogpeppefwereade: but maybe Destroy is appropriate there too.09:31
rogpeppefwereade: well, if you're removing a unit, it's going to take a while for the unit to actually shut down09:32
rogpeppefwereade: but if there's no responsible entity yet, perhaps it *should* be removed immediately09:32
fwereaderogpeppe, indeed so, but even then I'm not sure09:33
rogpeppefwereade: and Destroy could return before the entity is actually destroyed09:33
fwereaderogpeppe, I am pretty sure about Relation.Destroy and Service.Destroy09:33
fwereaderogpeppe, yeah, absolutely09:33
fwereaderogpeppe, (and that neither of those should have EnsureD* methods)09:34
fwereaderogpeppe, machines and units I am still very unsure about09:34
fwereaderogpeppe, I think that if a unit has an asisgned machine, we have to set it to Dying and let the MA make the more complex decisions09:35
rogpeppefwereade: i vote for having Destroy on all of them, and have Dying/Dead as an implementation detail (and something that's potentially watchable)09:35
rogpeppefwereade: definitely. a unit needs to be able to clean itself up, that's the whole point of all thise09:35
rogpeppethis09:35
rogpeppefwereade: i think Life makes sense, but EnsureDead/Dying not as much (or at all, perhaps)09:36
fwereaderogpeppe, ok, I think we are in agreement09:36
rogpeppefwereade: but the difficulty here is the distinction between Destroy and Remove.09:38
rogpeppefwereade: but... maybe we don't make that distinction09:40
rogpeppefwereade: we just make Destroy idempotent09:40
fwereaderogpeppe, I think it's ok -- Destroy might cause removal right away or it might not, but should always succeed absent corrupt state or network problems; removal09:40
rogpeppefwereade: so when a uniter sees Dying, it'll clean up stuff, then call Destroy again09:40
fwereaderogpeppe, I surely hope not09:41
rogpeppefwereade: and Destroy will itself call ensureDying on itself09:41
rogpeppefwereade: ?09:42
fwereaderogpeppe, I don't understand what you're expecting Destroy to do -- but I *think* that while the unit is still assigned to a machine, it should do nothing, and the machine is the thing responsible for calling RemoveUnit once the unit is dead09:43
fwereaderogpeppe, so the unit does somehow cause itself to become Dead09:43
fwereaderogpeppe, but that is, I think, not as simple as justsetting a flag09:43
rogpeppefwereade: if the user calls juju remove-unit, what should that call in state?09:45
fwereaderogpeppe, Unit.Destroy()09:45
rogpeppefwereade: " while the unit is still assigned to a machine, it should do nothing"09:45
rogpeppefwereade: so how does remove-unit work then?09:45
fwereaderogpeppe, calling it *again* should do nothing, because no interesting state has changed apart from the unit being Dying rather than Dead, which I don't think is relevant09:46
rogpeppefwereade: ok, so how does the unit actually get removed from state?09:47
fwereaderogpeppe, it depends... either by Destroy (if it's not assigned to anything and therefore has no responsible entity) or by the MA once the unit has set itself to Dead09:48
rogpeppefwereade: how does the MA do it?09:48
fwereaderogpeppe, RemoveUnit?09:48
rogpeppefwereade: so we've got Destroy, which *may* call RemoveUnit, and RemoveUnit, which is *sometimes* appropriate to call09:49
rogpeppefwereade: i'm wondering if we need RemoveUnit09:49
fwereaderogpeppe, we definitely need RemoveUnit, how else are we going to handle service removal?09:50
fwereaderogpeppe, (that's not implemented either ofc :/)09:50
rogpeppefwereade: what if Destroy removes the unit when it can?09:50
fwereaderogpeppe, it does -- in that case, that also has to be responsible for service cleanup09:51
rogpeppefwereade: why's that?09:51
fwereaderogpeppe, who else is going to do it?09:51
rogpeppefwereade: (removing a unit never removes a service, does it?)09:51
fwereaderogpeppe, it should09:51
rogpeppefwereade: i disagree09:51
rogpeppefwereade: it's perfectly ok to have a service with no units09:51
fwereaderogpeppe, no shit09:52
rogpeppefwereade: sure, we can have that right now09:52
fwereaderogpeppe, it's not ok to have a dying service with no units because nothing else is going ot clean it up09:52
fwereaderogpeppe, service is basically the same as relation09:52
rogpeppefwereade: ah, if the service is dying, sure09:52
fwereaderogpeppe, we need the same txn dance in AddUnit/RemoveUnit/Destroy as we have for EnterScope/LeaveScope/Destroy with relations09:52
rogpeppefwereade: so what's wrong with having Unit.Destroy also responsible for service cleanup, if it finds that the service is dying.09:54
rogpeppe?09:54
fwereaderogpeppe, (sorry, I am feeling extremely grumpy about this, because I feel like I've been misled repeatedly about the impact of various decisions and that I have basically spent the last 3 months clearing up the shit that has been thrown over the wall to me under pretence of being "finished", and AFAICT I am going to have to basically rewrite state in order to complete subordinates)09:55
fwereaderogpeppe, Destroy can do that if the unit's unassigned, yes, but it's not the only thing that might need to do that09:55
rogpeppefwereade: to be fair, i think nobody understood the problem that well before, and it's difficult to write code to solve someone else's future problem.09:56
fwereaderogpeppe, in practice it's going to be something like unit.removeOps() that gets composed into bigger txns in a couple of places09:57
rogpeppefwereade: it's just like clearing the last refcount, yes? when anything that can be blocking a dying thing from become dead becomes dead itself, it must try to destroy the things that it might be blocking09:57
fwereaderogpeppe, yeah, exactly09:57
fwereaderogpeppe, this is not a non-obvious consequence of the model09:57
fwereaderogpeppe, it is something I was talking about back in lisbon 109:58
rogpeppefwereade: it's actually very similar to the refcounting i was talking about a long time ago09:58
fwereaderogpeppe, and I think I am somewhat legitimately pissed off that the problem has just been ignored09:58
rogpeppefwereade: i always felt a bit fuzzy (in a not good way) about the lifecycle stuff, but i felt i didn't have enough handle on the actual problem to propose something better.09:59
rogpeppefwereade: how about this: delete all Remove* calls, and replace them with Destroy calls.10:00
rogpeppefwereade: also remove all EnsureDead and EnsureDying methods10:00
rogpeppefwereade: then Destroy always has a clear responsibility - move towards removing the entity from state.10:01
fwereaderogpeppe, I don't think I'm willing to put my weight behind an alternative one-size-fits-all solution -- I think that's the fundamental prblem10:01
rogpeppefwereade: and any entities that might also be in the process of destruction that depend on it.10:02
rogpeppefwereade: can you think of anything that can't be made fit that model, in a reasonably sane way?10:03
fwereaderogpeppe, different kinds of unit destruction?10:03
fwereaderogpeppe, especially since niemeyer has rejected the txn idea for that10:03
rogpeppefwereade: i really think that's something that's a mode of dying that can be implemented as a flag on the unit itself.10:04
fwereaderogpeppe, and wants to add new lifecycle flags and have multiple responsible entites running concurrently  instead10:04
fwereaderogpeppe, well, that is a possibility10:05
rogpeppefwereade: i think that whether to use transactions or not is up to the implementation of each entity10:05
rogpeppefwereade: i think Destroy as a catch-all entry point could make sense.10:06
rogpeppefwereade: because that's what we're actually trying to do, after all10:06
fwereaderogpeppe, I just don't get in what universe it is sane to have two different pieces of code fighting over which one is responsible for the backing state10:06
rogpeppefwereade: (well, we'd probably have ForceDestroy on units)10:06
fwereaderogpeppe, as an entry point, yeah, I think I'm +110:07
rogpeppefwereade: i think we're inevitably going to have two different pieces of code fighting over responsibility, because agents can become temporarily (and perhaps permanently) divorced from the state they're supposed to be responsible for10:08
rogpeppefwereade: and that's the big issue around --force10:08
fwereaderogpeppe, right -- but we agreed a long time ago that the unit should watch for its own Deadness, and that that would be the signal that it was to Stop Doing Everything10:09
fwereaderogpeppe, Life=Dead is, explicitly, the responsibility handover point10:09
rogpeppefwereade: sure. just as Dying is such a signal, right?10:09
rogpeppefwereade: (is there any difference between Dying and Dead there, in fact?)10:10
fwereaderogpeppe, if we set a unit to Dead the worst that will happen is one spurious error and restart before it cleanly shuts down10:10
fwereaderogpeppe, if we do some funky dying flag then we have two entities fighting over who gets to do what10:10
fwereaderogpeppe, and I refuse to believe that that is a sensible way to manage things10:10
rogpeppefwereade: do you think you can do the entire unit clean up (leaving all relations) in a single transaction?10:11
rogpeppepw10:11
fwereaderogpeppe, I think it'll be hard, and ugly, but I don't think it'll be impossible, or noticeably uglier than any other options10:12
rogpeppefwereade: surely all you need to do is make leaving scope idempotent?10:13
rogpeppefwereade: then who cares if two entities are doing it at the same time?10:13
rogpeppefwereade: and it doesn't need to be hard, or ugly.10:13
rogpeppefwereade: and it's a sufficiently rare case that efficiency is of no concern at all10:14
fwereaderogpeppe, it offends me that a unit agent can have state that it depends on secretly whipped out from under its feet by another entity10:16
rogpeppefwereade: but that's what force is all about, surely?10:16
rogpeppefwereade: and it's not great, but sometimes it's the only option10:17
fwereaderogpeppe, it's about not giving the charm notice to clean up -- not about fucking up our internal state10:17
fwereaderogpeppe, I think that if there's some way we can implement it without dropping ideas of ownership out of the window, we should do so10:17
rogpeppefwereade: we're talking force majeur here. that's not an issue, i believe.10:17
rogpeppefwereade: this will only be used when we really don't care about the unit's internal state any more10:18
fwereaderogpeppe, I may be misunderstanding what you mean by "unit's internal state", but I don't think we can ever say we don't care about it...10:19
rogpeppefwereade: if i use remove-unit --force, surely that's giving license to the system to remove the unit regardless of its current state.10:20
fwereaderogpeppe, yeah -- but that doesn't mean we can ignore that state, the removal still needs to keep state consistent10:21
rogpeppefwereade: even if you use transactions, you're still potentially whipping state out from under the unit agent's feet10:21
fwereaderogpeppe, yeah, in a way that uniter has been designed to handle from the beginning10:22
fwereaderogpeppe, because we discussed this, and agreed it, and so I implemented it10:22
rogpeppefwereade: so what are you worried that it *won't* deal with correctly?10:23
rogpeppefwereade: when a unit is dying, what needs to happen before it actually dies? is it just that it needs to leave relation scopes?10:23
fwereaderogpeppe, and deal with its subordinates10:23
fwereaderogpeppe, which will themselves have scopes to leave10:24
rogpeppefwereade: so if a unit finds itself dying, it sets its subords to dying and waits for them to die before dying itself?10:26
fwereaderogpeppe, the necessary txn will not be entirely trivial to compose, but I really think that adding more states for more entities and distributing the cleanup responsibilities amongst more entities (each of which could themselves fail at arbitrary times) is a bad move10:27
fwereaderogpeppe, I think that setting a unit to Dying should also set its subordinates to Dying10:27
rogpeppefwereade: is that possible to do in one transaction?10:28
fwereaderogpeppe, I think a unit should not be able to become dead while it has subordinates...10:28
fwereaderogpeppe, don't see why not10:28
fwereaderogpeppe, what problems are you anticipating?10:28
* rogpeppe reminds himself of the transaction capabilities10:30
rogpeppefwereade: don't you need to know the doc id that will be updated before starting the transaction?10:32
rogpeppefwereade: so you can't do an equivalent of "UPDATE life=Dying WHERE principal==myUnit"10:32
fwereaderogpeppe, no: I do it for everything in doc.Principals, assert no changes to what I composed the txn from, and retry on abort10:34
rogpeppefwereade: ah, so you could assert that subordinates haven't changed (by looking in unitDoc.Subordinates)10:35
rogpeppefwereade: so, just to be clear, what state *have* you anticipated changing under the feet of the uniter?10:40
fwereaderogpeppe, Life becoming Dead10:42
fwereaderogpeppe, this can cause arbitrary failures if we're unlucky, but I *think* that's fine, because when we come up again we handle Dead correctly10:42
fwereaderogpeppe, basically, when the unit becomes Dead, it will complete its current operation if possible, and not do anything else ever again10:44
rogpeppefwereade: so to make that work, you need to set dead and remove all relations, all in the same transaction?10:44
rogpeppes/remove/leave/10:44
fwereaderogpeppe, yeah10:45
fwereaderogpeppe, but the relations are not the hard bit10:45
fwereaderogpeppe, well, they're not trivial10:45
rogpeppefwereade: oh yeah, and set subords to dead and leave all their relations too10:45
rogpeppefwereade: all in the same transaction10:45
fwereaderogpeppe, but nor are they going to be impossible to handle -- it's doing all that for N units that really bothers me10:45
rogpeppefwereade: istm this might be pushing the boundaries of the transaction system a little10:45
fwereaderogpeppe, do you have any idea what those boundaries actually are? how many ops is too many?10:47
rogpeppefwereade: i suppose the uniter could see that the "force" flag is set, and treat that as the same as it currently sees Dead10:47
fwereaderogpeppe, yeah, indeed, but niemeyer was -1 on that for no reason I could determine10:47
rogpeppefwereade: no idea at all. just that a thousand might pushing it, and isn't beyond the bounds of possibility10:48
rogpeppefwereade: apart from anything else, it'll act as a bottleneck in the system until the whole transaction goes through10:48
fwereaderogpeppe, yeah, I don't have a clear enough idea of the details to know what sort of impact that'll have10:50
rogpeppefwereade: it seems like something we should avoid if we can10:51
fwereaderogpeppe, yeah, maybe, I just feel like the alternatives are being handwaved a bit10:54
rogpeppefwereade: you're right, they are, 'cos we don't know the uniter details like you do :-)10:55
fwereaderogpeppe, heh, yeah10:57
rogpeppefwereade: istm that if there was something the uniter could see that it would treat as it currently treats Dead but isn't *actually* Dead, then things could work ok10:57
rogpeppefwereade: and it wouldn't change too many of the current uniter assumptions10:57
fwereaderogpeppe, yeah, but niemeyer rejected that suggestion :/10:57
rogpeppefwereade: perhaps you didn't phrase it in a sufficiently sympathetic way :-)10:58
fwereaderogpeppe, it's really tedious doing development with all these invisible walls10:58
rogpeppefwereade: agreed. did you ever look at my api spike branch BTW?10:58
fwereaderogpeppe, I did, but I didn't quite get my head around it properly I'm afraid :(10:59
rogpeppefwereade: that's fine. you're not the only one.10:59
fwereaderogpeppe, :)10:59
rogpeppefwereade: probably means it really is crack after all10:59
rogpeppefwereade: the rpc thing is perhaps too magical10:59
rogpeppefwereade: but it does make it *really* easy to write rpc servers...11:00
fwereaderogpeppe, I'm not sure -- I just wasn't able to flush my other thoughts and properly engage with it11:01
rogpeppefwereade: gustavo's not keen; i'm not entirely surprised.11:02
AramI've looked at your branch, though not as thoroughly to write a review. I like the way you are supposed to use the abstractions provided. feels very easy to me. I can't comment on the abstraction implementation yet, though.11:04
rogpeppeAram: the implementation is still (deliberately) very sketchy currently, although still reasonably neat. in particular it doesn't deal with any kind of concurrency at all yet.,11:05
rogpeppeAram: thanks for the response though - that's the first positive remark i've had yet!11:06
AramI don't think your branch is overkill. I believe that the problem at hand is not trivial, and doing it ad hoc is opening a can of worms. using your thing I'm sure we could change it in time as needed, but an ad hoc wrapper is bound by its initial implementation.11:08
rogpeppeAram: that's my thought too. but building general mechanisms and then using them seems to frowned upon in these parts.11:09
rogpeppeAram: there are a few things the hierarchical nature of the rpc thingy makes potentially possible too - caching being one of them. and you can get a reasonable-looking HTTP interface for free too, even if you decide to use gob for agent communication.11:11
Aramgoing to buy some bread.11:13
niemeyerMorning all11:14
niemeyerAram: Have a good, erm.. bread? :)11:14
rogpeppeniemeyer: hiya11:14
niemeyerrogpeppe: Yo11:14
niemeyerfwereade: Pingous11:15
fwereadeniemeyer, heyhey11:15
niemeyerfwereade: Heya11:15
fwereadeniemeyer, how's it going?11:15
niemeyerfwereade: I think a machine should be Dyiable (ugh) when there are still units11:15
niemeyerErm11:15
niemeyerShould not11:15
rogpeppeniemeyer: +111:16
niemeyerfwereade: I thought we already enforced that constraint11:16
fwereadeniemeyer, cool, I think the consequences are unpleasantr11:16
niemeyerfwereade: But perhaps it got lost in the changes11:16
fwereadeniemeyer, state enforces almost no constraints :/11:16
fwereadeniemeyer, ok, that is an overstatement11:16
niemeyerfwereade: Really? .. Okay :-)11:16
rogpeppeniemeyer: we've never set any constraints on setting something to Dying, only Dead, i think.11:16
niemeyerrogpeppe: The constraint was on removal11:17
niemeyerrogpeppe: I think11:17
niemeyerAt least I have fresh memories (perhaps fake) that it was impossible to remove a machine with units in it11:17
rogpeppeniemeyer: that's not quite the same thing as setting it to dying though11:17
niemeyerrogpeppe: It actually is, in terms of intent11:18
niemeyerrogpeppe: I mean what we previously did as "remove" and what we now do as "set to dying"11:18
niemeyer            if topology.has_machine(internal_id):11:19
niemeyer                if topology.machine_has_units(internal_id):11:19
niemeyer                    raise MachineStateInUse(machine_id)11:19
niemeyerMemories aren't entirely fake, at least11:19
rogpeppeniemeyer: yeah, it doesn't look like we make any checks like that currently11:20
rogpeppeniemeyer: even in RemoveMachine11:20
rogpeppeniemeyer: which is definitely wrong11:20
rogpeppeniemeyer: if we can't set a machine to dying unless it has no units, do we actually need Dying and Dead for a machine? we could just remove it.11:21
rogpeppeniemeyer: (assuming removal will fail if the machine has units)11:21
niemeyerrogpeppe: I don't understand how that constraint changes things with regards to the machine lifecycle11:22
niemeyerrogpeppe: It's still not alright to remove state under agents that are running11:22
rogpeppeniemeyer: true11:23
niemeyer-               if hasUnits {11:25
niemeyer-                       return fmt.Errorf("machine has units")11:25
niemeyer-               }11:25
niemeyer-               return t.RemoveMachine(key)11:25
niemeyerRemoveMachine was actually implemented like that11:26
rogpeppeniemeyer: in cmd/juju ?11:26
niemeyerrogpeppe: In state11:26
niemeyerThis was lost with the implementation of lifecycle support11:26
rogpeppeniemeyer: ah. that's racy of course, but still. i'm surprised we didn't have tests for that behaviour11:27
niemeyerrogpeppe: No, it actually wasn't11:27
fwereadeniemeyer, rogpeppe: I think removal is the PA's responsibility, so we do need Dead11:27
rogpeppeniemeyer: ah, 'cos it was in a retry loop?11:27
niemeyerrogpeppe: Yep11:27
niemeyerfwereade: Yeah, the constraint is a minor red-herring that we do need still11:28
rogpeppecould someone remind me again why agents can remove their own entities?11:28
rogpeppes/can/can't/11:28
niemeyerrogpeppe: A unit container doesn't magically go away because it removed the entity, same thing for a machine11:28
niemeyerrogpeppe: While the resource still exists, the respective management object should also exist11:29
rogpeppeniemeyer: ok, that's a useful maxim11:29
fwereadeniemeyer, rogpeppe: and I'm not even certain that Dying is *really* meaningless -- but I don't know what a machine agent's responsibility is other than to set itself to Dead11:29
niemeyerfwereade: Agreed, it can easily receive attributes that have to be accomplished before death11:30
fwereadeniemeyer, rogpeppe: given that we agree that it shoudn't have units when it's set to Dying11:30
rogpeppefwereade: it provides a hook for the machine agent to do something more sophisticated later11:30
niemeyerWe haven't really invested much in the machine management so far11:30
niemeyerfwereade: Well, actually..11:31
fwereadeniemeyer, rogpeppe: so I *think* that for machines we have constraints on EnsureDying, and a Machiner that just sets itself to Dead at an opportune moment, and that can be extended in future11:31
niemeyerfwereade: Removing units!11:31
fwereadeniemeyer, ah, we don't agree that?11:31
fwereadeniemeyer, the units must be removed before the machine is set to Dying, mustn't they?11:31
fwereadeniemeyer, so, yeah, the machiner won't want to set itself to dead while it still has units deployed11:32
fwereadeniemeyer, but it won't become Dying until that process is underway11:32
niemeyerfwereade: It's a good question, actually11:32
niemeyerfwereade: But that's perhaps an easier first step11:33
fwereadeniemeyer, would you expand? sounds like I'm missing something :)11:33
niemeyerfwereade: In theory it would be fine to set a machine to dying when all units are also dying11:33
fwereadeniemeyer, ah, yes, good point11:33
fwereadeniemeyer, I don't think that hurts us much, though, we still need to wait to recall all our units before we can become dead11:34
fwereadeniemeyer, whoops no that's crack11:34
fwereadeniemeyer, they won't be removed from state until they're recalled11:34
niemeyerfwereade: Sure, but how's that an issue?11:35
fwereadeniemeyer, with the current model, we need to wait for that to happen before we can make the machine Dying, so we dodge that problem11:35
niemeyerfwereade: Right11:35
fwereadeniemeyer, if we allow dying machine with dying units, then we need to hang around11:35
niemeyerfwereade: Which is easier, agreed11:35
niemeyerfwereade: Yep11:35
niemeyerWe don't have to do that now11:35
fwereadeniemeyer, you know, I think we do, for the uniter with subordinates11:36
fwereadeniemeyer, maybe I'm wrong, but I think that setting a unit to dying should also set all it subordinates to dying11:41
niemeyerfwereade: +111:41
niemeyerfwereade: Or,11:41
niemeyerfwereade: It can reject, but that sounds a bit weird11:42
niemeyerfwereade: Setting subordinates to dying is probably the right thing to do11:42
Aramniemeyer, bread with sweet crispy bacon goodness.11:42
fwereadeniemeyer, I'm pretty sure that's wrong -- the only other way to get rid of the subordinates is to kill the relation, isn't it?11:42
niemeyerfwereade: Indeed11:43
fwereadeniemeyer, cool11:43
niemeyerAram: Poor bread! ;-)11:44
* rogpeppe should probably have some breakfast too11:46
mrammgood morning all12:54
fwereademramm, heyhey12:57
TheMuemramm: Morning12:57
mrammwho all is planning to come to this morning's team meeting?12:59
mrammI will add you to the invite12:59
fwereademramm, I am12:59
dimiternmramm: me too12:59
Aramme too13:05
Arammramm, can you add me13:07
Aram?13:07
Aramfwereade, dimitern ^ ^13:08
dimiternAram: i'm not sure how?13:08
Aramping mark13:09
mrammdone13:09
Aramthx13:09
mrammdimitern: you are loved13:12
dimitern:)13:12
Arammac os x sucks13:14
mrammaram: http://mergy.org/2012/12/irecognition-i-am-no-longer-apples-target-market/13:21
fwereadeniemeyer, btw, there was something else I vaguely wanted to mention re LXC: AIUI, we *can* run, eg, precise i386 containers on quantal amd64... and this strikes me as an interesting complication for constraints (and the Deployer...) that I had not hitherto considered13:47
fwereadeniemeyer, but I don't think I'm in a position to anticipate it properly atm, and I guess I can't usefully worry about it until we have some actual containers to use13:47
fwereadeniemeyer, just running the host OS will be a lot simpler and get us a long way13:48
niemeyerfwereade: Agreed. I think the very first thing we should do is to not even worry about containers, but just do plain co-location14:05
fwereadeniemeyer, +114:05
niemeyerfwereade: I did consider the use of containers across releases before, but I did the same as you, and thought "Yeah, we should support that.", but discarded any kind of deep thinking as premature14:05
fwereadeniemeyer, yeah, I'd only really considered it re local provider before14:06
fwereadeniemeyer, rogpeppe, TheMue: https://codereview.appspot.com/6862053 is a rough proposal for making state testing a little clearer: it's not ready to go in, because it we're going to use it we should do so consistently, but I think the general idea is can be judged as it stands14:27
rogpeppefwereade: looking14:27
fwereadeniemeyer, rogpeppe, TheMue: some tests it helps with more than others ofc14:27
TheMuefwereade: Will hava a look14:27
rogpeppefwereade: have you changed any of the test semantics in that CL?14:30
fwereaderogpeppe, I am confident that everything that was tested before is still tested, but the details have changed in a couple of places14:31
rogpeppefwereade: i'd be happier to check this large CL if the only changes, for this round at least, were just changing the existing tests to use the new primitives.14:32
rogpeppefwereade: otherwise i feel i'm trying to check two things at once, and there are quite a lot of changes.14:32
fwereaderogpeppe, true -- the other side of it is that I tried to do that, but some of the tests were too painful to maintain like that :)14:35
rogpeppefwereade: how about a CL that just changes the tests that you feel are worth changing, and reserve refactoring the other ones for another CL (maybe several)?14:36
fwereaderogpeppe, if the general idea is roughly accepted then when it's ready I imagine I will do it as a series of single-test-file CLs on top of one that introduces the vocabulary14:36
rogpeppefwereade: ah, ok14:36
rogpeppefwereade: in which case i'm +0.5. i can see it makes the tests briefer, but it's also less clear to see what's going on each individual test.14:37
fwereaderogpeppe, so not entirely without pain -- but I *think* it's easier to mentally check equivalence between X and Z directly than between X and Y and Y and Z in two steps14:37
fwereaderogpeppe, that is interesting to me14:37
fwereaderogpeppe, because my experience has been that the sheer number of characters in play is the biggest obstacle to understanding a test I'm not familiar with14:38
rogpeppefwereade: maybe you're right. and the test primitives do have quite intuitive mappings to underlying operations14:39
fwereaderogpeppe, and ISTM that there's enough repetition that learning a small simple vocabulary once is a clear win, even when some of the verbs only save a line14:39
rogpeppefwereade: yeah.14:39
TheMueI'm off for now, will return later.14:41
niemeyerfwereade: Sent a few comments14:43
fwereadeniemeyer, cool, thanks14:43
niemeyerfwereade: I'm being asked for lunch, so will have to continue afterwards14:43
fwereadeniemeyer, np, enjoy :)14:43
rogpeppeniemeyer: here's a bare-minimum API CL, just to get us off the ground. hopefully we can agree on at least this much as a starting point. https://codereview.appspot.com/688804816:20
niemeyerrogpeppe: Looking16:20
niemeyerrogpeppe: That's a great bootstrap16:28
rogpeppeniemeyer: cool16:29
rogpeppeniemeyer: it's still entirely compatible with what i did before, of course :-) :-)16:29
niemeyerrogpeppe: I bet :)16:29
niemeyerfwereade: What is a deployer.Context?16:32
niemeyerfwereade: I'm a bit confused by the fact there's a DeployerName16:32
niemeyerfwereade: I see some debate there as well, so maybe we'd benefit from a quick exchange on it16:33
fwereadeniemeyer, I'm really sorry -- cath's aunt is just about to arrive -- I will try to grab you later if that's ok?16:34
niemeyerfwereade: Oh, surely16:34
niemeyerfwereade: I'll see if I can comment on the CL itself, actually, in a way that does not bring confusing16:34
niemeyerconfusion16:34
fwereadeniemeyer, cheers :)16:34
fwereadeniemeyer, lovely, thanks16:34
rogpeppeniemeyer: DeployerName is the entity that the deployer is working on behalf of. in practice it will be the machine's entity name or a principal unit's entity name.16:37
niemeyerrogpeppe: I understand that much.. I don't understand why it's part of the interface it's in16:37
rogpeppeniemeyer: it's so that the deployer can know if it should should remove a deployed unit from the state when it disappears from the watcher list16:38
rogpeppeniemeyer: i think16:38
rogpeppeniemeyer: i chatted with fwereade a bit ago about this16:39
fwereadeniemeyer, sorry, back briefly -- the main reason is that I don't want to pass the deployer name (and maybe state info) into every context method16:41
fwereadeniemeyer, it seemed more obfuscatory than helpful to do so, despite the slightly odd arrangement16:41
fwereadeniemeyer, the Context is the thing that knows all about how to deploy; the Deployer just tells it what to deploy16:42
fwereadeniemeyer, maybe it would be cleaner to just drop it from the interface and duplicate it in the Deployer16:43
niemeyerfwereade: I'm still catching up on the details of how the interfaces are used, so I don't know for sure, but I'll add a note in either case just to let you know of how it felt16:45
niemeyer_fwereade: Review is out17:11
niemeyer_fwereade: It's great step forward, thanks17:11
fwereadeniemeyer_, awesome, cheers, all looks good -- really off for now :)17:19
fwereadeniemeyer_, (and, yeah, Manager works for me, it's just a name I basically dismiss out of hand :))17:20
rogpeppedimitern: you've got a review: https://codereview.appspot.com/6877054/17:33
dimiternrogpeppe: thanks!17:33
dimiternrogpeppe: in fact, I want to get rid of the interface altogether, but first I'll finish the refactoring of the tests17:34
rogpeppedimitern: +117:34
dimiternI'm making them more granular with a few ensureExists, ensureNotExist and remove - taking interface{} and calling the appropriate underlying API17:35
rogpeppedimitern: in general it's best to avoid functions/methods that use interface{}. why do you need it here?17:35
dimiternrogpeppe: I'll glad if you take a look once I propose the changes (tomorrow probably)17:35
dimiternI have this http://paste.ubuntu.com/1415180/17:37
dimiternrogpeppe: ^^17:37
rogpeppedimitern: i'm not convinced that's much gain over small simple statically typed functions tbh17:38
dimiternrogpeppe: well, if I don't have this then I end up with these huge test cases (Add/Has/Get/Remove in one, to be idempotent)17:40
rogpeppedimitern: i'm not arguing against helper functions, just that it's better IMHO to go with static typing where you can. something like this, for example? http://paste.ubuntu.com/1415205/17:48
dimiternrogpeppe: ok, can you explain why this is better? I'm not arguing, just curious17:49
rogpeppedimitern: then each function is evidently trivial17:49
rogpeppedimitern: it's better because the compiler will tell you when you get it wrong17:50
dimiternrogpeppe: I see, so it's better to write more code if it's static vs. less more generic code with type checks17:51
dimiternmore, but simpler, that is17:51
rogpeppedimitern: yeah. but in this case it might actually be less code in some case too17:52
rogpeppedimitern: ensureNotExist is 23 lines but as separate functions (not counting blank lines) it's 2017:53
dimiternrogpeppe: ok, I like it :) I'll change it17:53
rogpeppedimitern: every time i see "interface{}" i have to do a double-take, and wonder what's going on and what might be really happening at runtime.17:54
dimiternrogpeppe: like unhandled cases and unknown types, in addition - probably some run-time reflection overhead17:55
rogpeppedimitern: definitely. although performance is no issue here, of course.17:56
rogpeppedimitern: BTW your ensureExists function is a bit odd for the name it's given, especially paired with ensureNotExist. ensureExists makes sure that something exists; ensureNotExist checks if something doesn't currently exist.  i'd probably call it "add" :-)17:57
dimiternrogpeppe: I was unsure what's the proper name myself :) but yeah, add or create seems more appropriate given what it does17:59
rogpeppeniemeyer_: i've just been thinking about how we might manage our migration to using the API18:26
rogpeppeniemeyer_: i think we can do it quite nicely in an incremental way and reap some of the benefits early on18:27
rogpeppeniemeyer_: my thought is to implement jujud server, and get it running, even though we have no (well, one!) API calls yet.18:27
rogpeppeniemeyer_: then add an APIState field to juju.Conn, and have juju.NewConn connect to the API state too.18:28
rogpeppefwereade: how does that sound to you?18:29
rogpeppemramm: i think this is similar to the approach you were suggesting, and i think it's actually not much problem to do.18:30
mrammrogpeppe: yea, that's what I was thinking about in general18:31
mrammhaving an incremental migration path for clients18:31
rogpeppethen we can gradually migrate anything that uses juju.Conn to use calls in Conn.APIState (juju status might  be a nice early candidate, as it would be significantly speeded up by the API)18:31
rogpeppefinally, state/api can be renamed to state, and the existing State API can be made a private part of it.18:33
rogpeppeanyway, it's eod for me now18:33
rogpeppemramm, all: g'night18:34
niemeyer_rogpeppe: What woudl be APIState?18:53
niemeyer_rogpeppe: Either way, big +1 on the overall idea of having it working end-to-end from the get-go18:53
rogpeppeniemeyer_: APIState would be the type i've defined as api.State19:25
=== niemeyer_ is now known as niemeyer
mrammI will likely be about 5 minutes late for our team meeting... Can somebody else start up the google hangout?21:53
davecheneyhello, is it meeting time ?22:05
wallyworlddavecheney: i started a hangout https://plus.google.com/hangouts/_/01030a125de04a2af6a02a552ef3090109b438d5?authuser=0&hl=en22:06
wallyworldmramm: ^^^^22:06
davecheneywallyworld: can you add me as a super friend on g+, https://plus.google.com/u/1/103860539990722557379/posts22:09
wallyworldsure22:09
davecheneytwo secs22:12
davecheneysound is AFU22:12
mrammkk22:12

Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!