More Documentation

This commit is contained in:
Liam Young
2021-10-25 11:39:49 +01:00
parent 099228a18c
commit 6aca27172a
4 changed files with 359 additions and 12 deletions

5
ops-sunbeam/README.rst Normal file
View File

@@ -0,0 +1,5 @@
Advanced Sunbeam OpenStack
`How to Write a charm with ASO <howto-write-charm.rst>`_.
`ASO Concepts <concepts.rst>`_.

View File

@@ -3,7 +3,8 @@ New API Charm
=============
The example below will walk through the creation of a basic API charm for the
OpenStack `Glance <https://wiki.openstack.org/wiki/Glance>`__ service.
OpenStack `Glance <https://wiki.openstack.org/wiki/Glance>`__ service designed
to run on kubernetes.
Create the skeleton charm
=========================
@@ -33,10 +34,10 @@ Amend charmcraft file to include git at build time:
parts:
charm:
build-packages:
- git
- git
Metadata
~~~~~~~~
Add Metadata
============
The first job is to write the metadata yaml.
@@ -59,16 +60,16 @@ The first job is to write the metadata yaml.
- openstack
- storage
- misc
containers:
glance-api:
resource: glance-api-image
resources:
glance-api-image:
type: oci-image
description: OCI image for OpenStack Glance (kolla/glance-api-image)
requires:
shared-db:
interface: mysql_datastore
@@ -84,7 +85,7 @@ The first job is to write the metadata yaml.
interface: glance
ceph:
interface: ceph-client
peers:
peers:
interface: glance-peer
@@ -100,21 +101,332 @@ The requires section lists all the relations this charm is reliant on. These
are all standard for an OpenStack API charm plus the additional ceph relation.
Common Files
~~~~~~~~~~~~
============
ASO contains some common files which need to copied into the charm.
.. code:: bash
cp advanced-sunbeam-openstack/tox.ini charm-glance-operator/tox.ini
cp advanced-sunbeam-openstack/requirements.txt charm-glance-operator/requirements.txt
cp -r advanced-sunbeam-openstack/templates charm-glance-operator/src/
cp advanced-sunbeam-openstack/shared_code/tox.ini charm-glance-operator/
cp advanced-sunbeam-openstack/shared_code/requirements.txt charm-glance-operator/
cp -r advanced-sunbeam-openstack/shared_code/templates charm-glance-operator/src/
cp advanced-sunbeam-openstack/shared_code/.stestr.conf charm-glance-operator/
cp advanced-sunbeam-openstack/shared_code/test-requirements.txt charm-glance-operator/
At the moment the wsgi template needs to be renamed to add incluse the
service name.
.. code:: bash
cd charm-glance-operator
mv /src/templates/wsgi-template.conf.j2 ./src/templates/wsgi-glance-api.conf.j2
There are some config options which are common accross the OpenStack api charms. Since
this charm uses ceph add the ceph config options too.
.. code:: bash
cd advanced-sunbeam-openstack/shared_code/
echo "options:" > ../../charm-glance-operator/config.yaml
cat config-api.yaml >> ../../charm-glance-operator/config.yaml
cat config-ceph-options.yaml >> ../../charm-glance-operator/config.yaml
Fetch interface libs corresponding to the requires interfaces:
.. code:: bash
cd charm-glance-operator
charmcraft fetch-lib charms.nginx_ingress_integrator.v0.ingress
charmcraft fetch-lib charms.sunbeam_mysql_k8s.v0.mysql
charmcraft fetch-lib charms.sunbeam_keystone_operator.v0.identity_service
charmcraft fetch-lib charms.sunbeam_rabbitmq_operator.v0.amqp
charmcraft fetch-lib charms.observability_libs.v0.kubernetes_service_patch
Templates
=========
Much of the glance configuration is covered by common templates which were copied
into the charm in the previous step. The only additional template for this charm
is for `glance-api.conf`. Add the following into `./src/templates/glance-api.conf.j2`
.. code::
###############################################################################
# [ WARNING ]
# glance configuration file maintained by Juju
# local changes may be overwritten.
###############################################################################
[DEFAULT]
debug = {{ options.debug }}
transport_url = {{ amqp.transport_url }}
{% include "parts/section-database" %}
{% include "parts/section-identity" %}
[glance_store]
default_backend = ceph
filesystem_store_datadir = /var/lib/glance/images/
[ceph]
rbd_store_chunk_size = 8
rbd_store_pool = glance
rbd_store_user = glance
rados_connect_timeout = 0
rbd_store_ceph_conf = /etc/ceph/ceph.conf
[paste_deploy]
flavor = keystone
Charm
=====
This is subject to change as more of the common code is generalised into aso.
Inherit from OSBaseOperatorAPICharm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start by creating a charm class that inherits from the `OSBaseOperatorAPICharm`
class which contains all the code which is common accross OpenStack API charms.
.. code:: python
#!/usr/bin/env python3
"""Glance Operator Charm.
This charm provide Glance services as part of an OpenStack deployment
"""
import logging
from typing import List
from ops.framework import StoredState
from ops.main import main
import advanced_sunbeam_openstack.cprocess as sunbeam_cprocess
import advanced_sunbeam_openstack.charm as sunbeam_charm
import advanced_sunbeam_openstack.core as sunbeam_core
import advanced_sunbeam_openstack.relation_handlers as sunbeam_rhandlers
import advanced_sunbeam_openstack.config_contexts as sunbeam_ctxts
from charms.observability_libs.v0.kubernetes_service_patch \
import KubernetesServicePatch
logger = logging.getLogger(__name__)
class GlanceOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
"""Charm the service."""
ceph_conf = "/etc/ceph/ceph.conf"
_state = StoredState()
service_name = "glance-api"
wsgi_admin_script = '/usr/bin/glance-wsgi-api'
wsgi_public_script = '/usr/bin/glance-wsgi-api'
def __init__(self, framework):
super().__init__(framework)
self.service_patcher = KubernetesServicePatch(
self,
[
('public', self.default_public_ingress_port),
]
)
The `KubernetesServicePatch` module is used to expose the service within kubernetes
so that it is externally visable. Hopefully this will eventually be accomplished by
Juju and and can be removed.
Ceph Support
~~~~~~~~~~~~
This glance charm with relate to Ceph to store uploaded images. A relation to Ceph
is not common accross the api charms to we need to add the components from ASO to
support the ceph relation.
.. code:: python
@property
def config_contexts(self) -> List[sunbeam_ctxts.ConfigContext]:
"""Configuration contexts for the operator."""
contexts = super().config_contexts
contexts.append(
sunbeam_ctxts.CephConfigurationContext(self, "ceph_config"))
return contexts
@property
def container_configs(self) -> List[sunbeam_core.ContainerConfigFile]:
"""Container configurations for the operator."""
_cconfigs = super().container_configs
_cconfigs.extend(
[
sunbeam_core.ContainerConfigFile(
[self.service_name],
self.ceph_conf,
self.service_user,
self.service_group,
),
]
)
return _cconfigs
def get_relation_handlers(self) -> List[sunbeam_rhandlers.RelationHandler]:
"""Relation handlers for the service."""
handlers = super().get_relation_handlers()
self.ceph = sunbeam_rhandlers.CephClientHandler(
self,
"ceph",
self.configure_charm,
allow_ec_overwrites=True,
app_name='rbd'
)
In the `config_contexts` `sunbeam_ctxts.CephConfigurationContext` is added to the list
of config contexts. This will look after transalting some of the charms
configuration options into Ceph configuration.
In `container_configs` the `ceph.conf` is added to the list of configuration
files to be rendered in containers.
Finally in `get_relation_handlers` the relation handler for the `ceph` relation is
added.
OpenStack Endpoints
~~~~~~~~~~~~~~~~~~~
`OSBaseOperatorAPICharm` makes assumptions based on the self.service_name but a few
of these are broken as there is a mix between `glance` and `glance_api`. Finally the
charm needs to specify what endpoint should be registered in the keystone catalgue
each charm needs to explicitly state this as there is a lot of variation between
services
.. code:: python
@property
def service_conf(self) -> str:
"""Service default configuration file."""
return f"/etc/glance/glance-api.conf"
@property
def service_user(self) -> str:
"""Service user file and directory ownership."""
return 'glance'
@property
def service_group(self) -> str:
"""Service group file and directory ownership."""
return 'glance'
@property
def service_endpoints(self):
return [
{
'service_name': 'glance',
'type': 'image',
'description': "OpenStack Image",
'internal_url': f'{self.internal_url}',
'public_url': f'{self.public_url}',
'admin_url': f'{self.admin_url}'}]
@property
return 9292
Bootstrap
~~~~~~~~~
Currently ASO does not support database migrations, this will be fixed soon but until
then add a db sync to the bootstrap process.
.. code:: python
def _do_bootstrap(self):
"""
Starts the appropriate services in the order they are needed.
If the service has not yet been bootstrapped, then this will
1. Create the database
"""
super()._do_bootstrap()
try:
container = self.unit.get_container(self.wsgi_container_name)
logger.info("Syncing database...")
out = sunbeam_cprocess.check_output(
container,
[
'sudo', '-u', 'glance',
'glance-manage', '--config-dir',
'/etc/glance', 'db', 'sync'],
service_name='keystone-db-sync',
timeout=180)
logging.debug(f'Output from database sync: \n{out}')
except sunbeam_cprocess.ContainerProcessError:
logger.exception('Failed to bootstrap')
self._state.bootstrapped = False
return
Configure Charm
~~~~~~~~~~~~~~~
The container used by this charm should include `ceph-common` but it currently does
not. To work around this install it in the container. As glance communicates with Ceph
another specialisation is needed to run `ceph-authtool`.
.. code:: python
def configure_charm(self, event) -> None:
"""Catchall handler to cconfigure charm services."""
if not self.relation_handlers_ready():
logging.debug("Defering configuration, charm relations not ready")
return
for ph in self.pebble_handlers:
if ph.pebble_ready:
container = self.unit.get_container(
ph.container_name
)
sunbeam_cprocess.check_call(
container,
['apt', 'update'])
sunbeam_cprocess.check_call(
container,
['apt', 'install', '-y', 'ceph-common'])
try:
sunbeam_cprocess.check_call(
container,
['ceph-authtool',
f'/etc/ceph/ceph.client.{self.app.name}.keyring',
'--create-keyring',
f'--name=client.{self.app.name}',
f'--add-key={self.ceph.key}']
)
except sunbeam_cprocess.ContainerProcessError:
pass
ph.init_service(self.contexts())
super().configure_charm(event)
# Restarting services after bootstrap should be in aso
if self._state.bootstrapped:
for handler in self.pebble_handlers:
handler.start_service()
OpenStack Release
~~~~~~~~~~~~~~~~~
This charm is spefic to a particular release so the final step is to add a
release specific class.
.. code:: python
class GlanceWallabyOperatorCharm(GlanceOperatorCharm):
openstack_release = 'wallaby'
if __name__ == "__main__":
# Note: use_juju_for_storage=True required per
# https://github.com/canonical/operator/issues/506
main(GlanceWallabyOperatorCharm, use_juju_for_storage=True)

View File

@@ -0,0 +1,26 @@
debug:
default: False
description: Enable debug logging.
type: boolean
os-admin-hostname:
default: glance.juju
description: |
The hostname or address of the admin endpoints that should be advertised
in the glance image provider.
type: string
os-internal-hostname:
default: glance.juju
description: |
The hostname or address of the internal endpoints that should be advertised
in the glance image provider.
type: string
os-public-hostname:
default: glance.juju
description: |
The hostname or address of the internal endpoints that should be advertised
in the glance image provider.
type: string
region:
default: RegionOne
description: Space delimited list of OpenStack regions
type: string

View File

@@ -4,3 +4,7 @@ git+https://github.com/canonical/operator@2875e73e#egg=ops
git+https://opendev.org/openstack/charm-ops-openstack#egg=ops_openstack
git+https://github.com/openstack-charmers/advanced-sunbeam-openstack#egg=advanced_sunbeam_openstack
lightkube
# These are only needeed if the charm relates to ceph
git+https://github.com/openstack/charm-ops-interface-ceph-client#egg=interface_ceph_client
# Charmhelpers is only present as interface_ceph_client uses it.
git+https://github.com/juju/charm-helpers.git#egg=charmhelpers