Little known feature: workload => juju communication


#1

Most people that have used Juju for a little while are quite familiar with the concept of the juju agents executing hooks in the charms to respond to juju lifecycle events.

What fewer people know is a command available on the workload machines to interact back with juju.

juju-run [options] [<unit-name>] <commands>

The juju-run command executes the command in a hook context of the specified unit.

How this works

The unit agent has an abstract domain socket open named after the unit itself. The juju-run executable connects to this socket and passes through the commands to run.

The agent then acquires the hook execution lock and creates a hook context, and then shells back out in that context to execute the commands using bash -s.

Note: Since juju-run executes the command in a hook context, the command runs as root. As such, the juju-run comand must be executed by root or through sudo.

Status Updates

One initial use-case for this was to be able to provide out of band status updates from the workload. As an example, let’s say I have an application deployed called foo, and there is a script that was installed by the charm that has a cron job that wants to set the status based on external events to the server.

juju-run foo/0 "set-status maintenance 'updating the frobulator'"

This status would be observable in juju status as soon as it is run. This allows charms to provide more immediate feedback rather than waiting for the periodic update-status hook call from the agent.

Webhooks

An additional use-case is for the charm to set up a webhook. For example providing updates to a charm on an external github update.

Let’s say we have a charm that runs a simple webhook service. The charms makes the webhook endpoint available to the public internet and is then registered with an external provider, like github.

When the webhook is called, the data payload of the webhook can be used to set configuration for the charm. The key here would be to use the leadership data bag. Only the leader can write into it, so some care is needed on deploy and messaging.

# hash variable set from data payload
juju-run foo/0 "leader-set hash=$hash"

This change would then cause the leader-settings-changed hook to be executed and the normal charm operations could then use that new hash value to go and pull from the upstream branch.


New Features and Changes in Juju 2.7
#2

Couple of examples in the wild:


#3

Great post, @thumper!

One of the things I use juju-run for regularly when troubleshooting issue is introspecting and managing relation data, as using juju run from the juju client requires many obscure environment variables to be set in order to make relation hooks work.

Let’s say you want to introspect the data that application foo unit 1 is sharing to unit 0 via it’s relation with an ID of “2”. First find the relation ID (I like to use the /var/lib/juju/agents/unit-X/state/relations directory as a shortcut to find the relation IDs and related units on the machine running the unit, but if there are multiple relations between apps, you may need to use ‘juju-run unit/X “relation-ids $interface_name”’ and ‘juju-run unit/x "relation-list -r "’ commands to find the specific relation to the unit you want) then you can run:

juju ssh foo/0
sudo juju-run foo/0 -r 2 --remote-unit foo/1 'relation-get [optional_key]'

Similarly, if you need to update relation data (perhaps during a debugging/troubleshooting session):

juju ssh foo/0
sudo juju-run foo/0 -r 2 --remote-unit foo/1 'relation-set key=value'

#4

This is great, thanks! :slight_smile:

I want to note, too, for others that might not know yet ( like I didn’t a second ago ), that this doc, especially the “Hook Tools”, section tells you all of the commands that you have access to in the juju-run context.