This guide is for anyone that wants to create the code that we call a charm; the part that does the work of installing and managing applications in a Juju model. Many charms exist in the Charm Store already, but if your favourite application isn’t covered or you would like to make your own spin on an existing charm, you will discover all the tools and information you need here.
For an example of a community-driven charm development project see the OpenStack Charm Guide.
- A Juju controller: If you have not used Juju before, it’s a good idea to start here.
- Python 3.x: it is possible to develop charms using other languages, but this guide focuses on Python-based development.
- Charm Tools: Command line utilities to make it easy to create, build, fetch and test charms. See the Charm Tools page for more information.
- Charm Helpers: A Python library that provides an extensive collection of functions for developers to reuse. Many common charm patterns are encapsulated in functions of this library. See Charm Helpers for details.
- This guide also uses the Vanilla PHP Forum software as an example.
Designing your charm
To begin writing a charm, you should have a good plan of how it’s going to be implemented, what configuration options you wish to expose to anyone deploying the charm, and what dependent charms (if any) it will be related to. It’s a good idea to start with a diagram.
This visual representation of your charm deployment will help to solidify the configuration, deployment, and management of your application. Take the following example:
Looking at this diagram we see the Vanilla charm with two units. The Vanilla application requires a relationship to a database using the “mysql” interface. The MariaDB charm implements the mysql interface, which fulfills the db relation and is already in the Store: https://jujucharms.com/mariadb.
Writing your charm
The fastest way to write a new charm is to build off of existing layers. This allows you to create code that is very focused on the application you are trying to implement.
Layers let you build on the work of other charmers, whether that work is in the form of other charms that you can extend and modify, interfaces that communicate with remote applications, or partial base layers that make managing dependencies much easier. And it does this in a consistent, repeatable, and incremental way.
The available layers and interfaces can be found at Juju Charm Layers Index. The
basic layer provides charm helpers Python library and the reactive framework that makes layers possible.
Reactive and layered charms
Another software paradigm is reactive programming. Do something when the state or conditions indicate. Juju offers the charms.reactive package to allow charms to be written in the reactive paradigm. In charms.reactive code execution is controlled by boolean logic. You can define when the conditions are right, run this code, or when something is not set, run different code or do nothing at all.
The idea of charm layers is to combine objects or data into more complex objects or data. When applied to Charms, layers allow you to extend or build off other charms to make more complex or useful charms. The
layer.yaml file in the root directory of the charm controls what layer(s) will be imported.
Creating a new layer
First off, you require a local charm repository in which to work. This involves creating three directories –
charms – and setting some environment variables.
layers directory contains the source code of the layered charm covered in our examples. The
interfaces directory is where you’d place any interface layers you may wish to write, and the
charms directory holds the assembled, ready to deploy charm.
export CHARM_DIR=$HOME/charms export LAYER_PATH=$CHARM_DIR/layers export INTERFACE_PATH=$CHARM_DIR/interfaces mkdir -p $LAYER_PATH $INTERFACE_PATH cd $CHARM_DIR/layers
Exporting the environment variables in this way only sets the variables for the current terminal. If you wish to make these changes persist, add the same export statements to a resource file that are evaluated when you create a new console such as ~/.bashrc depending on your shell.
Once in the layers directory clone the example charm layer - layer-vanilla:
git clone http://github.com/juju-solutions/layer-vanilla.git cd layer-vanilla
If you’d like to write your own layer, or simply learn more about how layers are implemented, see How to Write a Layer.
Assemble the layers
Now that the layer is complete, let’s build it and deploy the final charm. From within the layer directory, this is as simple as:
The build will take all of the layers and interfaces included by your charm, either from your local
INTERFACE_PATH directories or automatically downloaded from the Juju Charm Layers Index and create a new charm in
build: Composing into /home/user/charms build: Processing layer: layer:basic build: Processing layer: layer:apache-php build: Processing layer: .
To inspect how the charm was assembled, there is a
charm layers command that shows what file belongs to which layer. Change to the charm directory and view the layer map:
cd $CHARM_DIR/trusty/vanilla charm layers
Then we can deploy mariadb and the new charm:
juju deploy mariadb juju deploy $CHARM_DIR/trusty/vanilla --series trusty juju add-relation mariadb vanilla juju expose vanilla
Add GUI user notes
Optionally leave some notes for those users who will deploy the charm from the Juju GUI. This consists of including a Markdown-formatted file called
getstarted.md at the root of the charm’s directory. Once the charm (or bundle) is deployed, the file will be rendered and displayed to the user.
The file should include the user’s next steps. Here is a guideline for what to include:
- State prerequisites for various application features.
- Include instructions for achieving a working application at a rudimentary level.
- Provide links for further reading.
As for style, here are some pointers:
- Keep in mind that the user is reading this information from the GUI, so write accordingly.
- Do not over-complicate. This is a small beginners’ guide.
- Use available Markdown formatting features such as section headers, lists, and code blocks. See this Markdown help.
Finally, here is an example of a
Testing your charm
Because Juju is a large complex system, not unlike a Linux software distribution, there is a need to test the charms themselves and how they interact with one another. All new charms require tests that verify that the application installs, configures, scales and relates as intended. The tests should be self-contained, installing all the required packages so the tests can be run automatically with a tool called
bundletester. Similar to hooks the tests should be executable files in a
tests/ directory of the charm. While you can write tests in Bash or other languages, it is recommended to use the Amulet library, which makes it easy to write charm tests in Python.
For more information about writing tests please refer to the charm testing guide documentation.
Once you have finished testing your charm or bundle visit the Charm Store page and consider the following topics:
- Pushing to the store
- Releasing to channels
- Publishing your charm
- Sharing charms and bundles