As some of you may know, there’s a long-running discussion surrounding so-called holistic charming, as opposed to ‘charming with deltas’.
In a nutshell:
the Juju model is event-based, where each event notifies the charm of a single change in the juju model. Other parts of the state are accessible on a per-request basis by using hook tool calls. But the part of the juju model that has changed, that is what the event is about. If one writes charm logic only looking at the event at hand, we call that charming with deltas.
Sometimes it is easier to reason about charm logic if, instead of looking at the event the charm is being awakened by, we look at the ‘global’ state only. This is the holistic approach.
In reality, we typically use a combination of the two.
If you want to code holistically, that means having to fight with the Juju model in a number of ways. This has resulted in a sprawl of roll-your-own state-tracking solutions that, to use a common example, allow a charm to know whether a given relation is breaking, even outside of the context of the relation-broken hook that gave us that information in the first place.
A reductionist like me won’t be caught saying this in any other context than this, but sometimes the solution is a sprinkle of holism.
from charm.holism.v0.holism import Holism # a charm lib for now? holism = Holism() @holism class MyCharm(ops.CharmBase): ... # your regular charm code def some_method(self): relation = self.some_relation() unit = relation.units # some unit if holism.is_departing(relation, unit): # your logic here
How it works
Holism keeps track in stored state of the ‘known’ state of all relations the charm has received events about.
Holism answers the question: “last I heard, is …”
- … this relation alive?
- … this unit joining that relation?
- … this unit departing that relation?
- … this relation being broken?
It doesn’t matter what event you’re processing, the relation data will be updated delta by delta, so you can focus on the big picture instead of keeping track of the deltas.
If the charm has received a
foo-relation-created in the past (and, so far, no
foo-relation-broken), Holism will “know” that
foo exists and is alive.
If the charm has received a
foo-relation-joined in the past for unit
remote/1 (and, so far, no
foo-relation-departed for the same unit), Holism will “know” that
remote/1 is joining
Every event, Holism will clean itself up.
For example, if Holism sees a
foo-relation-broken, for the duration of that hook, Holism will believe that the relation exists but is in a
holism.get_relation('foo').is_breaking == True
However, if Holism has seen a
foo-relation-broken at some point in the past (and, so far and from that point onwards, no
foo-relation-created!) and, since then, some other event (any other event) has been processed, then Holism will believe that no
foo relation is active and exists.
In other words, while we’re processing
relation-broken, the relation still exists but is in a breaking state. The next time we’re awakened (no matter the reason), we’ll assume the relation has broken down (it is no longer in a breaking state: it simply is no more).
holism.get_relation('foo') # --> RelationNotFoundError!
- something with planned units
- other transient states other than relations?
The floor is yours.