Debugging Juju GUI / juju-core connection

The GUI communicates with the juju-core API backend using a secure WebSocket connection. Several operations are performed as the user starts a GUI session:

  • the GUI connects and authenticates to the API server;
  • the GUI subscribes to the juju-core “mega watcher” and starts listening for all state changes;
  • the GUI reacts to those changes (a.k.a. delta stream) updating its internal database;
  • when the user modifies the environment, the GUI makes the corresponding API calls, and waits for responses coming from juju-core.

Debugging those interactions is not straightforward, but some tools, described below, can simplify the process.

A precise environment

juju-core is released more or less every two weeks. Most of the time we need to bootstrap the environment using juju-core trunk, so that we can test the GUI against the newer changes in the API layer, e.g.:

go install -v launchpad.net/juju-core/...
$GOPATH/bin/juju bootstrap --upload-tools

The –upload-tools flag uploads the local juju-core binaries to the environment node. At this point, the best way to set up the GUI and connect it to the bootstrap node is deploying the Juju GUI charm. Here comes the first problem: the Juju GUI charm, at the time of this writing, only works on precise. What if your juju-core development environment is on quantal? The quantal tools are installed in the bootstrap node, but in practice they cannot be reused in other nodes. As a consequence, as far as I know, when starting the agent on the charm machine, juju-core installs the latest precise tools it finds in the cache. If juju-core was recently released this could just work, but often happens that some changes in juju-core trunk break the compatibility between the uploaded quantal tools and the precise ones taken from the cache. In this case, one solution is bootstrapping a precise environment.
In essence we need to compile and upload tools from precise: there can be many ways to do that, I ended up using a precise LXC container (which can seem convoluted but actually works and is fast enough to set up).

Create an LXC template in /etc/lxc/local.conf containing the following lines:

lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up

Create a precise LXC, binding your home directory:

sudo lxc-create -t ubuntu -n juju-precise -f /etc/lxc/local.conf -- \
-r precise -a `dpkg-architecture -qDEB_HOST_ARCH` -b $USER

Start the container:

sudo lxc-start -n juju-precise -d

SSH into the container and install some required packages (from now on, all operations are intended to be run inside the LXC container).

sudo apt-get update && sudo apt-get upgrade
sudo apt-get install language-pack-en
sudo apt-get install bzr bzrtools build-essential python-software-properties

Add the Gophers PPA to package sources:

sudo apt-add-repository ppa:gophers/go && sudo apt-get update

Install golang, taking version 1.0.3 from the Gophers PPA

sudo apt-get install golang-stable

At this point, since your home directory is shared between the host and the container, you should already have the GOPATH environment variable set up.
We need to rebuild juju-core from precise, and therefore we need to delete the existing quantal binaries. I guess there are better ways to do this, but this is what I came up with:

rm -rf $GOPATH/pkg/linux_amd64
go install -v launchpad.net/juju-core/... launchpad.net/goamz/... \
launchpad.net/goose/...

Time to bootstrap the new precise environment, and deploy the Juju GUI charm into it:

$GOPATH/bin/juju bootstrap --upload-tools
$GOPATH/bin/juju deploy cs:~juju-gui/precise/juju-gui
$GOPATH/bin/juju expose juju-gui
$GOPATH/bin/juju status

Debugging

The first step is exposing the GUI branch we want to debug, e.g.:

$GOPATH/bin/juju set juju-gui juju-gui-source=lp:juju-gui

The easiest way to check the API logs is to use the debug-log command, recently reintroduced in juju-core (hooray!):

$GOPATH/bin/juju debug-log

Trying to log in from the GUI you will see something like:

domU-12-31-39-0C-24-F7:2013/04/04 09:44:28 DEBUG JUJU:jujud:machine api: <- {"Request": "Login", "Params": {"Password": "passwd", "AuthTag": "user-admin"}, "Type": "Admin", "RequestId": 0}
domU-12-31-39-0C-24-F7:2013/04/04 09:44:28 DEBUG JUJU:jujud:machine api: -> {"RequestId":0,"Response":{}}

The debug-log includes delta events. Anyway, you can also use the short Python script in http://pastebin.ubuntu.com/5676102/: it connects to the bootstrap node address (passed as first argument), authenticates to the API server, and subscribes to the mega watcher, printing to stdout (using a more readable formatting) new events as they arrive.