3
This is the base layer for all charms [built using layers][building]. It
4
provides all of the standard Juju hooks and runs the
5
[charms.reactive.main][charms.reactive] loop for them. It also bootstraps the
6
[charm-helpers][] and [charms.reactive][] libraries and all of their
7
dependencies for use by the charm.
11
To create a charm layer using this base layer, you need only include it in
15
includes: ['layer:basic']
18
This will fetch this layer from [interfaces.juju.solutions][] and incorporate
19
it into your charm layer. You can then add handlers under the `reactive/`
20
directory. Note that **any** file under `reactive/` will be expected to
21
contain handlers, whether as Python decorated functions or [executables][non-python]
22
using the [external handler protocol][].
24
### Charm Dependencies
26
Each layer can include a `wheelhouse.txt` file with Python requirement lines.
27
For example, this layer's `wheelhouse.txt` includes:
31
charmhelpers>=0.4.0,<1.0.0
32
charms.reactive>=0.1.0,<2.0.0
35
All of these dependencies from each layer will be fetched (and updated) at build
36
time and will be automatically installed by this base layer before any reactive
39
Note that the `wheelhouse.txt` file is intended for **charm** dependencies only.
40
That is, for libraries that the charm code itself needs to do its job of deploying
41
and configuring the payload. If the payload itself has Python dependencies, those
42
should be handled separately, by the charm.
44
See [PyPI][pypi charms.X] for packages under the `charms.` namespace which might
45
be useful for your charm.
49
Each layer has a reserved section in the `charms.layer.` Python package namespace,
50
which it can populate by including a `lib/charms/layer/<layer-name>.py` file or
51
by placing files under `lib/charms/layer/<layer-name>/`. (If the layer name
52
includes hyphens, replace them with underscores.) These can be helpers that the
53
layer uses internally, or it can expose classes or functions to be used by other
54
layers to interact with that layer.
56
For example, a layer named `foo` could include a `lib/charms/layer/foo.py` file
57
with some helper functions that other layers could access using:
60
from charms.layer.foo import my_helper
65
Any layer can define options in its `layer.yaml`. Those options can then be set
66
by other layers to change the behavior of your layer. The options are defined
67
using [jsonschema][], which is the same way that [action paramters][] are defined.
69
For example, the `foo` layer could include the following option definitons:
72
includes: ['layer:basic']
73
defines: # define some options for this layer (the layer "foo")
74
enable-bar: # define an "enable-bar" option for this layer
75
description: If true, enable support for "bar".
80
A layer using `foo` could then set it:
83
includes: ['layer:foo']
85
foo: # setting options for the "foo" layer
86
enable-bar: true # set the "enable-bar" option to true
89
The `foo` layer can then use the `charms.layer.options` helper to load the values
90
for the options that it defined. For example:
93
from charms import layer
97
layer_opts = layer.options('foo') # load all of the options for the "foo" layer
98
if layer_opts['enable-bar']: # check the value of the "enable-bar" option
99
hookenv.log("Bar is enabled")
102
You can also access layer options in other handlers, such as Bash, using
103
the command-line interface:
109
function do_thing() {
110
if layer_option foo enable-bar; then
111
juju-log "Bar is enabled"
112
juju-log "bar-value is: $(layer_option foo bar-value)"
116
reactive_handler_main
119
Note that options of type `boolean` will set the exit code, while other types
124
This layer provides hooks that other layers can react to using the decorators
125
of the [charms.reactive][] library:
130
* `leader-settings-changed`
136
Other hooks are not implemented at this time. A new layer can implement storage
137
or relation hooks in their own layer by putting them in the `hooks` directory.
139
**Note:** Because `update-status` is invoked every 5 minutes, you should take
140
care to ensure that your reactive handlers only invoke expensive operations
141
when absolutely necessary. It is recommended that you use helpers like
142
[`@only_once`][], [`@when_file_changed`][], and [`data_changed`][] to ensure
143
that handlers run only when necessary.
145
# Layer Configuration
147
This layer supports the following options, which can be set in `layer.yaml`:
149
* **packages** A list of system packages to be installed before the reactive
150
handlers are invoked.
152
* **use_venv** If set to true, the charm dependencies from the various
153
layers' `wheelhouse.txt` files will be installed in a Python virtualenv
154
located at `$CHARM_DIR/../.venv`. This keeps charm dependencies from
155
conflicting with payload dependencies, but you must take care to preserve
156
the environment and interpreter if using `execl` or `subprocess`.
158
* **include_system_packages** If set to true and using a venv, include
159
the `--system-site-packages` options to make system Python libraries
160
visible within the venv.
162
An example `layer.yaml` using these options might be:
165
includes: ['layer:basic']
170
include_system_packages: true
176
This layer will set the following states:
178
* **`config.changed`** Any config option has changed from its previous value.
179
This state is cleared automatically at the end of each hook invocation.
181
* **`config.changed.<option>`** A specific config option has changed.
182
**`<option>`** will be replaced by the config option name from `config.yaml`.
183
This state is cleared automatically at the end of each hook invocation.
185
* **`config.set.<option>`** A specific config option has a True or non-empty
186
value set. **`<option>`** will be replaced by the config option name from
187
`config.yaml`. This state is cleared automatically at the end of each hook
190
* **`config.default.<option>`** A specific config option is set to its
191
default value. **`<option>`** will be replaced by the config option name
192
from `config.yaml`. This state is cleared automatically at the end of
193
each hook invocation.
195
An example using the config states would be:
198
@when('config.changed.my-opt')
199
def my_opt_changed():
207
This layer currently does not define any actions.
210
[building]: https://jujucharms.com/docs/devel/authors-charm-building
211
[charm-helpers]: https://pythonhosted.org/charmhelpers/
212
[charms.reactive]: https://pythonhosted.org/charms.reactive/
213
[interfaces.juju.solutions]: http://interfaces.juju.solutions/
214
[non-python]: https://pythonhosted.org/charms.reactive/#non-python-reactive-handlers
215
[external handler protocol]: https://pythonhosted.org/charms.reactive/charms.reactive.bus.html#charms.reactive.bus.ExternalHandler
216
[jsonschema]: http://json-schema.org/
217
[action paramters]: https://jujucharms.com/docs/stable/authors-charm-actions
218
[pypi charms.X]: https://pypi.python.org/pypi?%3Aaction=search&term=charms.&submit=search
219
[`@only_once`]: https://pythonhosted.org/charms.reactive/charms.reactive.decorators.html#charms.reactive.decorators.only_once
220
[`@when_file_changed`]: https://pythonhosted.org/charms.reactive/charms.reactive.decorators.html#charms.reactive.decorators.when_file_changed
221
[`data_changed`]: https://pythonhosted.org/charms.reactive/charms.reactive.helpers.html#charms.reactive.helpers.data_changed