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
developbranch of the Juju git repository - Make changes to the code
- Run a few tests locally:
make pre-checkgo 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
jujucommands 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: falseNote that there is also a
enable-os-refresh-updateoption 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: xenialYou 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.yamlwill 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>=DEBUGThis 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.
