My first attempts at python-libjuju


I was looking to get started with python-libjuju, mostly to help a customer with their python-libjuju issues.

I have been out of python for a number of years, so all the async stuff is new for me.

One of the things that had been asked for was how to deal with facades for elements supported in the API but not yet supported in python-libjuju.

In particular two parts were asked about:

  • juju trust
  • annotations

I thought it would be fun to start with a first hack at getting the annotations out for an application.

First I needed an application that had some annotations. Bundles allow setting them, so quickly created a simple bundle and deployed it.

    charm: cs:~jameinel/ubuntu-lite
    num_units: 1
      foo: bar

Next was a bunch of messing around with python and libraries.

Just used pip3 install juju to get the juju library. If there is a better way, we should document it somewhere.

From there I created a file called juju-annotation so I could use juju annotation to run it.

Put it up on github:

My next TODOs are:

  • support setting annotations
  • support machine annotations
  • support unit annotations
  • support model annotations

I would also like to get better annotation support into the native python-libjuju objects too.


Setting annotations is already supported via Application.set_annotations() (implementation), but there is not a corresponding way to read annotations, so adding that would be great.

It looks like the code you have in juju-annotation would be easy to integrate into an Application.get_annotations() method. It looks like we already have a model class for Annotation to represent the results, but it is missing any implementation. Honestly, though, annotation data seems simple enough to just model it as a simple Python dictionary; that’s what set_annotations() takes as input anyway.

As for trust, my first thought is that it should go on Application as well, but maybe it makes more sense on Model or Controller.


Looks like Machine.set_annotations() is also available, but neither Unit.set_annotations(), nor Model.set_annotations().

Also, for reference, if any of the facades or newer facade methods were unavailable, the Syncing Upstream Updates docs page describes how to sync against the Juju core code. The process for when this is done needs to be formalized to keep in sync with Juju changes, rather than being ad-hoc, as-needed as it is currently.


Settings are a little different to charm config in that all settings are map[string]string.

We should have a way to validate prior to sending it across to set.

Another question: is there anything already in python to validate a string as a valid machine, application or unit?

I’m not surprised that neither units nor modes have annotations defined as there has never been any use case for it before.


I think for trust, we should keep it on the Application, and have it as a property backed by code for setting and getting. There is application config that is added internally to manage trust implementation. So hooking it up should be pretty simple.

That say we should be able to have something like:

    myApp = model.application["name"]
    print("app trust value {}".format(
    # setting trust = true

The Juju Show #45 - Jujuna OpenStack upgrades tested

Put up a PR for adding full annotation support to python-libjuju,

A little unclear whether we could reduce the repetition… probably could with some external functions.

The annotations plugin has been updated to support the model, application, unit, and machine level annotations.

tim@terry:~/Canonical/juju-annotation (master)$ juju status
Model    Controller  Cloud/Region         Version  SLA          Timestamp
default  test        localhost/localhost  unsupported  15:02:04+13:00

App     Version  Status  Scale  Charm        Store       Rev  OS      Notes
ubuntu  18.04    active      1  ubuntu-lite  jujucharms    7  ubuntu  

Unit       Workload  Agent  Machine  Public address  Ports  Message
ubuntu/0*  active    idle   0          load: 0.22, 0.41, 0.60

Machine  State    DNS            Inst id        Series  AZ  Message
0        started  juju-ac1505-0  bionic      Running

tim@terry:~/Canonical/juju-annotation (master)$ juju annotation ubuntu
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation ubuntu my-field=value 'my-log=string with space' foo=bar
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation ubuntu
foo: bar
my-field: value
my-log: string with space
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation ubuntu/0
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation ubuntu/0 wat="I'm special"
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation ubuntu/0
wat: I'm special
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation 0
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation 0 type=machine
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation 0
type: machine
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation @model
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation @model for-whom=a-customer
tim@terry:~/Canonical/juju-annotation (master)$ juju annotation @model
for-whom: a-customer

The special entity @model is used to access the model annotations. It didn’t want it to match the application regex.


What do you think about using the command:

juju annotate

And have annotations show up in the show-x calls for things?

juju show-application ubuntu

my-field: value

I guess the issue there is the lack of a show-unit call currently.

For the model I’d go the route of -m model for now. I’m hesitant to start to add the @model concept as a special case that only works in annotations.

I’ll provide this in the PR as feedback but my thoughts. It’d also be good to have this supported as extra yaml in the bundle so that at the root of the bundle you could provide the annotations to be added to the model along with a machine. I wonder if there’s a place in there for the unit level ones as well.


the problem is we need to support
juju annotate -m model unit/0 foo=bar
I guess you’re saying that if you leave off any app or unit you end up annotating the model?


Yes, I was thinking much like

juju status -m something

It acts on the model but could also be more added like

juju status -m something application