Handling uninstallation upon subordinate removal in reactive

Dmitrii Shcherbakov dmitrii.shcherbakov at canonical.com
Tue Nov 21 16:01:54 UTC 2017

Hi Junien,

Using hooks in the reactive world is perfectly file - just use them

Think of a distinction between the "Juju world" and the "charm world".
Juju's unit agent is an integration point with your charm - the "charm
world" starts when a unit agent runs a charm code and ends when you run a
hook tool (for a moment until returns the result to the charm) or when the
charm process exits. A unit agent (literally) executes a file at
<charmdir>/hooks/<event-name> when an event happens. In most classic
(non-reactive) charms <event-name> is a symlink to <something>_hooks.py -
argument 0 of any executed Linux process will contain that symlink name
instead of a target python file name (e.g. "stop") - this is done so that
charm-helpers can route that to a decorated function @hooks.hook("stop")
via a library shim. This is just routing to the right code within a file.
The same happens with reactive, only the execution path will be unit agent
-> <charmdir>/hooks/<event-name> -> reactive library code -> @hook or
@when* execution.

If you look at any built reactive charm, it will have a generated "hooks"
directory with files that have identical contents for every event name -
they all get you to the reactive library "routing engine" first.


This engine then decides what to execute.

Hook template files are provided by layer-basic:


The "only implements those hooks" restriction comes from the fact that only
certain symlinks are provided and this makes sense to provide those in
layer-basic only as they do not have a relation context.


Other hooks are provided as well (again, with just a library entry point)
in subsequent layers (generated via charm-tools when you do `charm build`
based on metadata.yaml):


A natural question would be to ask why there are no "install" hook
implementations. This is a trick that most reactive charms use:

1. install event happens;
2. reactive library gets invoked;
3. when_not("installed") gets fired as this state is not set.

You could use any state instead of "installed", like when_not("foobar") and
install packages there - it's just not intuitive. Removal is different as
it is quite explicit (you don't really need a state for it).

Best Regards,
Dmitrii Shcherbakov

Field Software Engineer
IRC (freenode): Dmitrii-Sh

On Tue, Nov 21, 2017 at 5:58 PM, Junien Fridrick <
junien.fridrick at canonical.com> wrote:

> Hi,
> I'm developping a charm, and would like to know the best practive to
> do some uninstallation steps when a subordinate gets removed from a
> unit (these steps being : uninstall a snap)
> The only way I can think of is to use @hook('stop'), but as far as I
> remember, using hooks is not something one should do in the reactive
> world.
> Does anyone have any advice for doing that properly ?
> I was also thinking that maybe the snap layer could save which
> application installed which snap, and if said application is removed,
> then remove said snap. Would that be a good idea ?
> Thanks !
> --
> Juju mailing list
> Juju at lists.ubuntu.com
> Modify settings or unsubscribe at: https://lists.ubuntu.com/
> mailman/listinfo/juju
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/juju/attachments/20171121/c679fa41/attachment.html>

More information about the Juju mailing list