Note 6 May 2022: This post has some good info, but some things have changed over time. We’re now using go 1.18 and go mod, instead of deps.
Here are some notes that I’ve been collecting as my experience has grown since joining the Juju core team 2 months ago.
Pre-Setup
The first thing that I did when starting was play around with Juju as a user:
snap install --classic juju
This gave me some exposure to Juju’s terminology and concepts. It’s also been useful also in case I need to check to something works with a “known good” version while I write code and break things.
Creating a Development Environment
My personal setup (Canonical employees work remotely from home) is fairly straightforward:
- laptop (Dell XPS 15)
- VS Code
- Go 1.11
- GNU make 4.2
I found the Juju README quite helpful to get started. Luckily, Juju builds very easily via:
$ go get -d -v github.com/juju/juju/...
$ make dep
$ go install -v github.com/juju/juju/...
As it happens, this can be simplified further by simply running:
$ make install
You should now have a working Juju binary at $GOPATH/bin/juju
.
Workflow
My general pattern for fixing bugs:
- Branch from the
develop
branch of the Juju git repository - Make changes to the code
- Run a few tests locally:
make pre-check
go test ./path/to/folder/...
- Run all unit and integration tests via Canonical’s build infrastructure for Juju. This is activated by pushing to my local branch to Github, then creating a pull request.
When developing a new feature, I often need to experiment by live testing on a LXD cluster locally:
- Bootstrap locally with LXD:
juju bootstrap localhost testing
- Deploy a minimal workload:
juju deploy wiki-simple
- Make changes to the code (often including copious logging messages!)
- Follow the unit testing steps above
- Run the following commands:
- Create a new Juju binary:
make install
- Upload the new binary and upgrade the current system on the fly:
juju upgrade-model --build-agent
- Create a new Juju binary:
- Lower Juju’s logging levels:
juju model-config logging-config="juju.apiserver=TRACE;juju.api=TRACE;<root>=DEBUG"
- Evaluate the system by running
juju
commands with the--show-log --logging-config="<root>=TRACE"
arguments, e.g.juju --show-log --logging-config="<root>=TRACE" status
Extra tips
Feature Flags
Developing behind feature flags involves defining the flag, using it within the code base, then enabling it within the running juju
/jujud
binaries.
Speeding up local development
The juju bootstrap
command supports several configuration parameters, many of which are tailored for production environments. For local development, modifying the defaults can speed things up.
From the wiki page “Faster LXD”:
Turn off automatic package upgrades
By default Juju will run apt-get upgrade on machines it creates. While this is useful in production scenarios, it isn’t usually necessary for test deployments. Turning it off can greatly speed up deployments.
The relevant Juju configuration for this is:
enable-os-upgrade: false
Note that there is also a
enable-os-refresh-update
option which you might be tempted to disable but I’ve found this normally causes more problems than it’s worth (charms fail to install).
To make use of these configuration options, add them to juju bootstrap
and juju add-model
commands as command-line arguments:
juju bootstrap --config enable-os-upgrade=false
The whole invocation can become quite convoluted with the addition of feature flags:
JUJU_DEV_FEATURE_FLAGS=mongodb-snap juju --debug bootstrap --config enable-os-upgrade=false localhost c-snap
To mitigate some of this verbosity, it’s possible to add these configuration settings to your own cloud definition. Again, from the wiki page “Faster LXD”:
Suggested Juju config for LXD deployments
Here’s a complete suggested configuration for test LXD deployments that takes into account the ideas discussed in this article (as well as turning on DEBUG logging):
logging-config: "<root>=DEBUG" enable-os-refresh-update: true enable-os-upgrade: false default-series: xenial
You can keep this in a file and pass it as the --config option to juju bootstrap and juju add-model but a more > convenient approach is to create a custom LXD cloud with these options set. A section like this in
~/.local/share/juju/clouds.yaml
will define a LXD cloud called “dev”:clouds: dev: type: lxd config: default-series: xenial enable-os-refresh-update: true enable-os-upgrade: false logging-config: <root>=DEBUG
This can then be used like this:
juju bootstrap foo dev
Further Resources
- The full list of configuration parameters is available on docs.jujucharms.com, with a page for model config and controller config options.