sunbeam-charms/ops-sunbeam/doc/howto-pebble-handler.rst
Guillaume Boutry 822bfb0f50 Fix documentation typos
Change-Id: I6abc64755bff428543fdb22bd04ad217b1fa5ee9
2023-02-15 10:34:56 +01:00

131 lines
4.3 KiB
ReStructuredText

=============================
How-To Write a pebble handler
=============================
A pebble handler sits between a charm and a container it manages. A pebble
handler presents the charm with a consistent method of interaction with
the container. For example the charm can query the handler to check config
has been rendered and services started. It can call the `execute` method
to run commands in the container or call `write_config` to render the
defined files into the container.
Common Pebble handler changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ASO provides a pebble handler base classes which provide the starting point
for writing a new handler. If the container runs a service then the
`ServicePebbleHandler` should be used. If the container does not provide a
service (perhaps it's just an environment for executing commands that affect
other containers) then `PebbleHandler` should be used.
.. code:: python
import ops_sunbeam.container_handlers as sunbeam_chandlers
class MyServicePebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"""Manage MyService Container."""
The handlers can create directories in the container once the pebble is
available.
.. code:: python
@property
def directories(self) -> List[sunbeam_chandlers.ContainerDir]:
"""Directories to create in container."""
return [
sunbeam_chandlers.ContainerDir(
'/var/log/my-service',
'root',
'root')]
In addition to directories the handler can list configuration files which need
to be rendered into the container. These will be rendered as templates using
all available contexts.
.. code:: python
def default_container_configs(
self
) -> List[sunbeam_core.ContainerConfigFile]:
"""Files to render into containers."""
return [
sunbeam_core.ContainerConfigFile(
'/etc/mysvc/mvsvc.conf',
'root',
'root')]
If a service should be running in the container the handler specifies the
layer describing the service that will be passed to pebble.
.. code:: python
def get_layer(self) -> dict:
"""Pebble configuration layer for MyService service."""
return {
"summary": "My service",
"description": "Pebble config layer for MyService",
"services": {
'my_svc': {
"override": "replace",
"summary": "My Super Service",
"command": "/usr/bin/my-svc",
"startup": "disabled",
},
},
}
Advanced Pebble handler changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
By default the pebble handler is the observer of pebble events. If this
behaviour needs to be altered then `setup_pebble_handler` method can be
changed.
.. code:: python
def setup_pebble_handler(self) -> None:
"""Configure handler for pebble ready event."""
pass
Or perhaps it is ok for the pebble handler to observe the event but a
different reaction is required. In this case the method associated
with the event can be overridden.
.. code:: python
def _on_service_pebble_ready(
self, event: ops.charm.PebbleReadyEvent
) -> None:
"""Handle pebble ready event."""
container = event.workload
container.add_layer(self.service_name, self.get_layer(), combine=True)
self.execute(["run", "special", "command"])
logger.debug(f"Plan: {container.get_plan()}")
self.ready = True
self.charm.configure_charm(event)
Configuring Charm to use custom pebble handler
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The charms `get_pebble_handlers` method dictates which pebble handlers are used.
.. code:: python
class MyCharmCharm(NeutronOperatorCharm):
def get_pebble_handlers(self) -> List[sunbeam_chandlers.PebbleHandler]:
"""Pebble handlers for the service."""
return [
MyServicePebbleHandler(
self,
'my-server-container',
self.service_name,
self.container_configs,
self.template_dir,
self.openstack_release,
self.configure_charm,
)
]