This tutorial aims to show you the steps needed to prepare a charm, starting from just the bare needed Python code and ending in the proper Juju deploy, using both Operator Framework and Charmcraft projects.
Create the charm
To start a real project, we can rely on
charmcraft init to setup the base structures that we’ll need to construct a complete charm: a basic code we can extend (with its correspondent tests!), proper requirements files for our Python dependencies, the required
metadata.yaml, other configuration files we may need (like
actions.yaml) and other project files (like a README, LICENSE, etc).
But to understand all that info can be overwhelming, so let’s start with a more basic approach: as the bare minimum things we need to start are our charm code and the metadata file, let’s go with that.
For the purposes of this tutorial, we’ll go with a very simple Python code that doesn’t do anything special, just logs that it was installed properly, so we can see that the whole process is done.
Let’s see it, will explain the code below…
#!/usr/bin/env python3 import logging from ops.charm import CharmBase from ops.main import main logger = logging.getLogger(__name__) class MyCharm(CharmBase): def __init__(self, *args): super().__init__(*args) self.framework.observe(self.on.install, self.on_install) def on_install(self, event): logger.info("Congratulations, the charm was properly installed!") if __name__ == "__main__": main(MyCharm)
The overall structure is very simple: we have a couple imports (
logging is from Python’s stdlib, and
ops is the Operator Framework, we’ll see later how to make it available), then the logger at module level, our charm’s class, and the init at the end. Note that the class inherits from
CharmBase and then at the end we pass it to the framework’s
main: this is all we need to start using the Operator Framework.
In the charm class, after calling parent’s
__init__ (very important for the charm initialization), all we do is tell the framework to call our
on_install method when the
install event is triggered. The hooked method only logs that all succeeded.
Of course Juju also needs a
metadata.yaml file with some information about our project:
name: tutocharm summary: A charm for the tutorial. description: A simple and basic charm to show the Operator Framework and Charmcraft in a tutorial.
So, I put that content in the respective files (and made the
charm.py file executable):
$ tree . . ├── metadata.yaml ├── requirements.txt └── src └── charm.py 1 directory, 3 files
You may have spotted the
requirements.txt file in that tree. It’s where we can put all the Python dependencies we need. For this tutorial, we just included the Operator Framework, so the content of our requirements file is:
Build the charm
We’re ready to build our charm. For this we need the Charmcraft tool. Soon it will be ready as a snap, but for now we can use it from a virtual environment:
$ virtualenv --python=python3 env ... $ source env/bin/activate (env) $ pip install charmcraft ... Successfully installed charmcraft-0.0.1
Ready to use
charmcraft, then. Let’s build our charm:
(env) $ charmcraft build Done, charm left in 'tutocharm.charm'
That’s all we need.
Deploy the charm
The final step is deploy it, but before, in a different terminal, execute the following to see the logging we specified in the charm:
Back to the original terminal, let’s deploy our charm:
juju deploy ./tutocharm.charm
Wait some moments to let Juju do its magic, and at some point, in the
juju debug-log terminal, a line very similar to the following one will appear:
unit-tutocharm-1: 13:26:10 INFO unit.tutocharm/1.juju-log Congratulations, the charm was properly installed!