/srv/irclogs.ubuntu.com/2020/04/01/#smooth-operator.txt

t0mb0Hey stub, in the old reactive way of doing things if I wanted to execute a piece of code that configures something I'd just set some reactive state and configure a @when handler. Is the right pattern in the operator framework to create a custom EventBase and then register it with framework.observe? Are there examples of creating a custom event that isn't due to a juju hook or relationship state change?07:51
stubOne way is just to call the function directly.07:52
stubOtherwise, yeah, you define an event, register an observer, then fire the event when you want the observer to run07:53
t0mb0stub, right but atm I have a chicken and the egg problem where I need to wait for the pod to be ready before I can call the function07:53
stubI'm just deferring events in that case07:54
t0mb0stub, yeah that's what I'm doing too :(07:54
stub'if not_ready: event.defer(); return'07:54
t0mb0yeah I'm doing that too but it means I have to pass this event object around07:54
t0mb0i'd much rather just just set some state then signal a new event07:55
t0mb0than have to pass the event around and have massive callbacks07:55
t0mb0er callstack even07:55
stubWhy fire and event to trigger the observer, instead of calling it directly?07:56
stuboh, I guess you want to defer it there if things are not ready07:56
t0mb0yeah07:56
t0mb0I don't want to configure my application in the same function where I spin up the pod07:57
t0mb0I want to spin up the pod and issue a new event, say "init", then have my init handler just defer loop until the pod is live07:57
t0mb0I can get it to work, I wondered if there was a cleaner way than passing the even down the stack07:58
stubhttps://pastebin.ubuntu.com/p/pgGQKdkFVb/ is roughly how it should go08:04
stubIt gets more complex if you want to add behavior to your events or extra __init__ arguments08:04
stubhttps://pastebin.ubuntu.com/p/RHMcTQPJBv/ sorry (typo)08:06
t0mb0stub, so line 19 is where I am signalling an on.ants_in_my_pants event?08:06
stubYup08:06
t0mb0awesome thanks!08:07
stubSo the emit would happen after the pod_set_spec08:07
Chipacagood moring!08:13
Chipacamorning, also08:13
* Chipaca decides the typo is ominous and cancels the whole day08:13
jamat least it wasn't "mourning"08:17
Chipacaindeed08:18
niemeyerGood morning08:19
* niemeyer reads stub's pastebin and notices facubatista recent change will break people up08:20
niemeyerEvents was renamed to EventSet08:21
Chipacaniemeyer: which pastebin?08:22
niemeyerChipaca: There was a conversation here in the channel shortly before you joined08:22
mthaddonhttps://pastebin.ubuntu.com/p/RHMcTQPJBv/08:22
mthaddon^ that's the one08:22
Chipacata08:22
jamniemeyer, actually it doesn't break that code, as it is using CharmEvents and EventBase which didn't change.08:25
jambut yes, custom events on types that use EventsBase break unless we do something like "@deprecated\nEventsBase = EventSetBase"08:26
niemeyerjam: If it didn't change it must change, or we need to revert it.. CharmEvents needs to be CharmEventSet08:26
Chipacaniemeyer: https://github.com/canonical/operator/pull/191#issuecomment-60587591708:27
niemeyerOtherwise we're neither here nor there08:27
niemeyerChipaca: Well, yeah, that sounds like an awkward non-agreement08:28
niemeyerChipaca: You raised the inconsistency, jam said he liked the old naming better, facundo merged it08:28
t0mb0I have a requirement to store some secrets, previously we stored them as files inside the leader pod but I'd like to change that so we store these as k8s secrets, does the framework support that yet? I see in this example charm the developer has written his own k8s API https://github.com/majduk/charm-k8s-mongodb/tree/b0e55efd53d38abe26ea9deb271af9922b88b238/src08:28
t0mb0will the StoredState support this kind of thing?08:29
stubPersonally I'd revert given they are not sets (like set(), frozenset() or collections.abc.Set)08:29
Chipacastub: the issue is EventBase vs EventsBase08:30
niemeyerstub: Yeah, I think we should just revert it.. it sounds like multiple people don't agree the naming is better08:30
niemeyert0mb0: What API do you need to access?  We definitely want to grow the supported APIs over time08:32
stubIf we have CharmEvents, we can have ObjectEvents08:32
t0mb0niemeyer, the kubernetes secrets and configmaps08:33
Chipacastub: ooo08:33
Chipacaniemeyer: wdyt?08:33
t0mb0we're initialising a wordpress deployment with a random password and it'd be nice if we could expose that so operators can retrieve it if the pod dies08:34
niemeyerChipaca, stub: Sounds fine to me08:38
ChipacaPR coming up08:38
Chipacaniemeyer: another thing: the check for having multiple names for a single instance of a StoredState is bogus, never worked AFAICT, and is untested. Should I drop it, or change it to work and add tests?08:38
Chipacathis is for class C: foo=StoredState(); bar=foo08:39
jamChipaca, did you see my suggestion?08:41
Chipacajam: I did. I'll PR that up as well so we can discuss.08:41
jam(when iterating attributes, just don't exit on first discovery)08:41
Chipacaah08:41
Chipacano i did not see that one08:41
niemeyerChipaca: I see it as preventing an obvious invariant from being broken.. in which case would it be fine to ignore the invariant being wrong?08:41
jamthe real question is whether that actually works.08:41
jamniemeyer, the problem is that it doesn't actually find the invariant08:41
niemeyerjam: Invariants don't have to be looked for :)08:42
niemeyerjam: If the attribute name is wrong, this is all bogus..08:42
niemeyerjam: But I agree with your statement, we might look further to detect a bug08:43
Chipacaso I can change the code to not break out of the loop, and if it finds itself twice it'll catch that08:44
ChipacaI'll do that, and then run to the shops08:45
stubCan we have relids being relname:16 format again? I just spent ages tracking down a bug, where I was failing to retrieve data by relid because somewhere thought it should be str(15) instead of int(15)08:45
ChipacaI'll look at @deprecated after08:45
mthaddont0mb0: essentially we're talking about interacting with kubernetes secrets here (being able to store and retrieve them). I think filing an issue about that be the best way to go for now08:46
niemeyerstub: The relation ID is really the number.. the name is there to aid people when they are in a hook context. But in Python we have both the name and the ID at hand.08:46
niemeyermthaddon, t0mb0: +108:47
niemeyerAnd also +1 in supporting the API internally somehow08:47
* mthaddon nods - sounds good08:48
stubyeah, and and now I need to ensure nothing casts it to a string or it becomes a different key according to dictionary lookups. Just stuffing in a pile of asserts to see what fed me a string instead of an int.08:48
niemeyerstub: Good question.. please let me know when you find out. If we have other APIs manipulating these IDs independently, we definitely need to look into it.08:49
t0mb0stub, do you know if there is a maximum number of times an event will be reemitted?08:49
* stub shrugs08:49
jamt0mb0, under what circumstance? as in if you keep defer() then will it even not reemit ?08:50
niemeyerstub: This should only be an issue if you're running juju CLI commands next to the framework, in which case the answer would be to use the APIs in the framework08:51
niemeyerWe'll soon start talking directly to the agent, and allow iterating over multiple hook events if desired.. this will not work if one is interacting with the agent externally08:52
t0mb0jam, so i'm basically defer looping until self.model.get_binding('website').network.ingress_addresses[0] returns something08:52
t0mb0I'd expect juju debug-log to be spamming my logger statements but it doesn't08:53
jamt0mb0, the only thing that causes deferred events to reemit is another hook invocation. if you are deferring and then exiting the hook, you are waiting for the next hook to tell you to check.08:53
jamthat hook might  be 'config-changed' or 'update-status', but nothing that would 'spam the logs' as update-status is on a 5-min timer.08:54
t0mb0oh08:54
stubt0mb0: (and you won't see log.debug() level messages atm if they are missing entirely)08:56
jamt0mb0, generally state that you read from Juju won't change during the lifetime of a hook anyway (otherwise hooks have to check at the end of the hook if something is different than at the beginning of the hook)08:56
jamjuju generally fires another hook to let you know if stuff that you responded to changed (eg, you get 'config-changed' when config is different than the last time config-changed ran)08:57
t0mb0jam, so if I'm waiting for my pod to be active before resuming the rest of the config-changed stuff what should I be doing?08:57
jam(also, I think set-pod-spec doesn't take effect until the hook exits, either, but I know there was some question there)08:58
jamt0mb0, so I thought there was supposed to be an event if your IP address changes, which might match what you're hoping to do?09:00
jamJuju doesn't currently feed the charm operator the full k8s events, IIRC09:00
stubSounds like check if things are ready in a config-changed hook, and if not just wait for the next config-changed hook09:02
t0mb0jam, https://github.com/johnsca/charm-gitlab-k8s/blob/master/src/charm.py this charm makes use of a custom HTTPInterface is that what you're talking about?09:02
t0mb0stub, but there won't be another config-changed hook right? because you're returning from the on_config_changed function?09:04
t0mb0unless you do a self.on.config_changed.emit() or something similar?09:05
t0mb0if the state isn't set09:05
stubThere will be another config-changed hook when something changes that Juju wants to tell you about. So if it is sending one when the pod IP addresses change, you can wait until that config-changed hook is fired. Might not be the first, won't be the last.09:06
niemeyert0mb0: Also, this is normal code.. you don't have to (and most likely should not) have all of your logic living _inside_ the on_config_changed method09:07
niemeyerInstead, ideally code should be organized in methods and types that properly reflect what they are doing, and then you simply call them by their name whenever an appropriate situation shows up09:08
t0mb0niemeyer, that's how I roughly have it now, I'm checking to see if various variables on my state object are set and calling methods when they are and returning an event.defer() if they're not09:09
niemeyert0mb0: Yeah, if I get what you're saying that's a pattern I've seen repeatedly in charms, but it doesn't feel like a very nice way to organize code in general.. what I've seen looks like:09:10
niemeyer1) Ensure everything in the state and in the machine about everything the charm could possibly want to do is as it should be09:10
niemeyer2) Do everything the charm possibly would like to do based on other checks previously done09:11
niemeyerThe problem with this approach is that those several checks are detached from the code they actually "protect", and local encapsulation is broken down09:12
niemeyerA much better approach is to do things in smaller pieces, with local information.. for example, we want small components that are responsible for their own knowledge, and emit high-level events that are meaningful for what they do09:14
t0mb0niemeyer, so in that case I'd need k8s to tell Juju the pod is alive and ready so I can observe that event right?09:14
niemeyert0mb0: Yes, that definitely sounds like something we want to have more comfortable access to09:15
t0mb0niemeyer, i'm guessing that doesn't exist yet and I should raise an issue?09:15
niemeyert0mb0: Yes please.. but also, meanwhile let's find a nice way for you to move forward with your needs without being blocked on that issue09:16
t0mb0I feel like for initial setups of wordpress we don't mind waiting 5 minutes or so for another hook to run09:16
niemeyert0mb0: Also note that what I described above says more about the overall organization of the charm itself than about external needs09:18
niemeyert0mb0: In other words, improving things in that way doesn't need external events09:18
t0mb0niemeyer, yeah it makes sense. that's why i asked (s)tub about writing custom events earlier09:18
niemeyert0mb0: Right, we made events very easy to create and use precisely so we can reuse that form of encapsulation into our own custom components as well09:19
niemeyert0mb0: As a random example, it would make sense for example to have a MySQLServer endpoint handler that would consume the relation events, and emit higher-level on_database_available, etc09:20
niemeyerI'm somewhat surprised that the k8s support in juju doesn't inform the charm of the pod being ready.. I wonder what kind of pattern people have been using so far09:21
niemeyerDo people just fork off a daemon that keeps trying to do things with it?09:21
niemeyerI will be digging further into k8s in the coming days09:22
t0mb0niemeyer, it seems like the existing charms shy away from doing application initialisation and it's left to the user. I imagine you could bake initialisation logic into the docker image and then have some kind of lock to stop non leader pods from racing09:24
stubSo.... using the relation id as a dictionary key isn't great if you are going to convert it to json, cause it will be cast into a string and won't round trip09:24
niemeyerstub: Where's the json conversion taking place09:24
niemeyer?09:24
stubmy code09:25
stubstuffing a data structure into leadership settings in this case09:26
niemeyerI see09:26
stub>>> assert json.loads(json.dumps({1: True})) == {"1": True}09:26
stubsolution... stick to yaml :)09:26
niemeyerstub: Yeah, I'm surprised the json package doesn't complain about it09:26
niemeyer"Oh, sure.. here is your data completely different now sir."09:27
niemeyert0mb0: I'd like to significantly improve the control charms have over their workload containers09:28
niemeyert0mb0: That's one of my key goals over the next couple of cycles09:28
t0mb0niemeyer, I mean something like an "pod-ready" event/hook would be nice09:28
t0mb0once the readinessProbe is green09:29
niemeyerI need to get my hands dirty to get a better view of how we'll accomplish that09:29
niemeyert0mb0: Yeah, something like that as well09:30
Chipacaok, now yes, to the shops09:32
* Chipaca really really needs to go09:38
stubgit+ssh://git.launchpad.net/~stub/interface-pgsql/+git/operator seems to be working now if anyone wants a look. Unit tests next week.09:57
stubAnd the 'operator' branch of git+ssh://git.launchpad.net/~stub/plinth/+git/plinth-charm is a (private) non-k8s operator framework charm using it, still needing its actions wired up and a tidy10:03
* stub wanders off into the long weekend10:05
niemeyerstub: Thanks for the branches, and have fun!10:05
niemeyerstub: Or have a good isolation I guess :)10:05
stubI'm shopping for everyone tomorrow... got to keep my ancestors fed.10:06
niemeyerstub++10:08
Chipacajam: was @deprecated a suggestion to use https://pypi.org/project/deprecation/, or was it something else?11:06
jamChipaca, I think I looked at 2 or 3 different ways of doing deprecation. It feels a bit overdone to do deprecation before we hit a 1.0 but certainly I do think we want a *plan* around deprecation.11:07
jamIf we feel we need it from now, then we can11:07
jamChipaca, given the simplicity of deprecation, it would be nice to not need an external lib11:08
Dmitrii-ShAdded unit tests for a peer relation to one of my charm PRs: https://github.com/canonical/cockroachdb-operator/pull/1/commits/95c61ebf40eaf812eb46e4b90055f47f8545704e (they need PR #196 to be merged to pass because of the issue #202)11:25
Dmitrii-Shhttps://git.io/JvdO4 - TestCharmClass here is something worth discussing I think. The peer relation interface code expects a parent charm class to provide an event so that it can expose cluster id details on a relation when it happens. However, using the concrete CockroachDBCharm type in interface-specific unit tests is problematic because11:32
Dmitrii-Shinterface component events can trigger CockroachDBCharm handlers that do real work (such as writing config). Instead of using mocking, I am using CharmBase here but with an event set for CockroachDBCharm.11:32
Dmitrii-ShThis provides me with a way to still trigger CockroachDBCharm-specific events for the interface code to react to but without invoking the charm logic I don't need.11:33
jamDmitrii-Sh, so why isn't the code that depends on an event/generates an event a separate class? it doesn't have to be, but it might be interesting to think about keeping the Charm as only generating Juju events, and having something else that generates higher level events.11:38
Dmitrii-Shjam:  *thinking about how to rework it*. The first impression is that I would still have to avoid triggering handlers but only on a different type.12:18
Chipacaso many reviews to do12:31
Chipacaso little coffee12:31
Chipacaalso, PEP 999912:32
jamChipaca, so we should use foo,bar,baz,quux as animal-friendly alternatives?12:41
Chipacajam: I say we go anti-pep-9999 and make all our variables refer to animals being mutilated in 'orrible ways12:42
jamdeadbeef we have12:42
jamslaughterhouse12:42
Chipaca'foo' can become 'gib'12:43
jamDmitrii-Sh, so I would think you'd want abstractions for places that your code interacts with "other things" like the filesystem, and then in tests you would substitute an alternate implementation of those that doesn't actually interact with the system.12:51
Dmitrii-Shjam: ty, I see what you mean. The charm itself would only poke an implementation of this abstraction which I would replace in the test in some way.12:54
jamright12:57
jamcertainly you don't want your actual charm rewriting /etc/postgresql.conf while you are testing.12:57
niemeyerIs that PEP-9999: https://www.blackcomb-shop.eu/en-PT/skirt-craft-1904867pep-9999black/12:57
niemeyerIt's the first hit on Google at least..12:57
niemeyerIt's also no longer available, so we don't need to worry12:58
Chipacaniemeyer: https://github.com/gerritholl/peps/blob/animal-friendly/pep-9999.rst12:58
jamhttp://www.montypython.net/scripts/fruit.php "Self Defense Against Fruit" I don't know that one nearly as well.12:59
Chipacaniemeyer: aw, but bugs with side effects are my favourite!13:06
Chipacathey're the gift that carry on giving!13:06
niemeyerI know.. I also like how colorful they are :)13:10
Chipacaniemeyer: got a couple of questions about debug-hook, after talking with rick h and reading through the discussion on the spec14:46
Chipacaniemeyer: if you have 15 minutes to a half hour that'd be good14:48
Chipaca(non-overlapping holidays + feature freeze means I'm trying to get this sorted myself, rather than wait for facubatista to be back)14:49
niemeyerChipaca: I'm just off a call.. if you have time in ~5 minutes, I'll prepare a mate and we can dive into it14:50
Chipacaniemeyer: sgtm14:50
niemeyerAlright15:01
niemeyerChipaca: Standup?15:03
Chipacaniemeyer: omw15:03
Chipacaniemeyer: i'll ping you for a meet as soon as i get out of my next one15:26
jamChipaca, oth15:45
jamChipaca, anything I can hepl with?15:45
Chipacajam: if you're around, you're welcome to join15:47
Chipacajam: but it is rather late for you15:47
jamtrue enough, though I wouldn't worry terribly about having the Charmcraft code finished for Juju feature freeze.15:50
Chipacajam: so I hear :)15:51
Chipacajam, niemeyer, standup meet if you could15:53
Chipacajam: very optional for you15:53
jamI can give it a few mins15:53
niemeyerI need a couple of minutes, but will be there15:53
Chipacacrazy day today16:24
Chipacai got to do 0 of Dmitrii-Sh's reviews16:25
Chipacai also got to run 016:25
Chipacai'm going to go run because daylight is nearly over, then make dinner, then review some things16:26
Chipacattfn!16:26
niemeyerEnjoy!16:27
Dmitrii-ShWould be good to get more eyes on this one - https://github.com/canonical/operator/issues/206. It seems to ask for `goal-state`-like functionality but I suggested a different idea.17:56
Dmitrii-Shthis seems to be a common problem when it comes to setting up stateful applications - you need to know whether to have one or multiple units at the beginning of a unit lifetime to initialize a cluster state from the initial cluster unit. In some cases this is merely about setting an initial replication factor to 1 vs 3 (or some other value).18:00
jamDmitrii-Sh, I'm of the mind that we should let them know about it. But the other option is to have 'we've told you what we're going to tell you for now' events that let you make progress.18:35
jameg, "start" will be called after all the relation-created18:35
jamso having some form of "we're done telling you about relation-joined for now"18:35
jambut relation-joined is blocked on the units actually coming up, and doesn't let you know what the admin's *intent* of deployment is18:36
Dmitrii-Shjam: yes, it feels like a unit need reasonable checkpoints with enough data about the overall model to make progress. Most importantly, at the beginning of a lifetime where inital state is created.19:03
Dmitrii-Shone other use-case that comes to mind besides clustering is setting up TLS19:04
Dmitrii-Shat the beginning it is important not to have any exchanges without TLS between units if the end goal is to have TLS enabled19:05
Dmitrii-Shyou might later decide to remove a relation with a particular CA charm that generates certs/keys and choose another but this is unlikely to change quickly19:06
niemeyerThere are different ideas intermixed here19:26
niemeyerWe already discussed this (jam and myself) a while ago and we both seem to agree that having a number of units as a hint, and a created relation hook, sorts out a good part of the desire19:27
niemeyerWe should avoid having something like goal state, though, as it creates a mixed and confusing reality for the unit19:28
niemeyerAnother part of what's described above sounds like just configuration19:28

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