Add peer relation and handler

This commit is contained in:
Liam Young 2021-10-13 09:49:14 +01:00
parent 72d2ae29eb
commit 27a54f4098
5 changed files with 146 additions and 1 deletions

View File

@ -99,6 +99,12 @@ class OSBaseOperatorCharm(ops.charm.CharmBase):
self.default_public_ingress_port,
self.configure_charm)
handlers.append(self.ingress)
if self.can_add_handler('peers', handlers):
self.peers = sunbeam_rhandlers.BasePeerHandler(
self,
'peers',
self.configure_charm)
handlers.append(self.peers)
return handlers
def get_pebble_handlers(self) -> List[sunbeam_chandlers.PebbleHandler]:
@ -206,6 +212,14 @@ class OSBaseOperatorCharm(ops.charm.CharmBase):
"""Determine whether the service has been boostrapped."""
return self._state.bootstrapped
def leader_set(self, key: str, value: str) -> None:
"""Set data on the peer relation."""
self.peers.set_app_data(key, value)
def leader_get(self, key: str) -> str:
"""Retrieeve data from the peer relation."""
return self.peers.get_app_data(key)
class OSBaseOperatorAPICharm(OSBaseOperatorCharm):
"""Base class for OpenStack API operators"""

View File

@ -0,0 +1,89 @@
#!/usr/bin/env python3
import logging
import typing
from ops.framework import EventBase
from ops.framework import EventSource
from ops.framework import Object
from ops.framework import ObjectEvents
from ops.framework import StoredState
class PeersRelationCreatedEvent(EventBase):
"""
The PeersRelationCreatedEvent indicates that the peer relation now exists.
It does not indicate that any peers are available or have joined, simply
that the relation exists. This is useful to to indicate that the
application databag is available for storing information shared across
units.
"""
pass
class PeersDataChangedEvent(EventBase):
"""
The CharmPasswordChangedEvent indicates that the leader unit has changed
the password that the charm administrator uses.
"""
pass
class PeersEvents(ObjectEvents):
peers_relation_created = EventSource(PeersRelationCreatedEvent)
peers_data_changed = EventSource(PeersDataChangedEvent)
class OperatorPeers(Object):
on = PeersEvents()
state = StoredState()
def __init__(self, charm, relation_name):
super().__init__(charm, relation_name)
self.relation_name = relation_name
self.framework.observe(
charm.on[relation_name].relation_created,
self.on_created
)
self.framework.observe(
charm.on[relation_name].relation_changed,
self.on_changed
)
@property
def peers_rel(self):
return self.framework.model.get_relation(self.relation_name)
@property
def _app_data_bag(self) -> typing.Dict[str, str]:
"""
"""
return self.peers_rel.data[self.peers_rel.app]
def on_created(self, event):
logging.info('Peers on_created')
self.on.peers_relation_created.emit()
def on_changed(self, event):
logging.info('Peers on_changed')
self.on.peers_data_changed.emit()
def set_app_data(self, key, value) -> None:
"""
"""
self._app_data_bag[key] = value
def get_app_data(self, key) -> None:
"""
"""
return self._app_data_bag.get(key)
def get_all_app_data(self) -> None:
"""
"""
return self._app_data_bag

View File

@ -27,6 +27,7 @@ import charms.mysql.v1.mysql as mysql
import charms.sunbeam_rabbitmq_operator.v0.amqp as sunbeam_amqp
import charms.sunbeam_identity_service_operator.v0.identity_service \
as sunbeam_id_svc
import advanced_sunbeam_openstack.interfaces as sunbeam_interfaces
logger = logging.getLogger(__name__)
@ -304,3 +305,37 @@ class IdentityServiceRequiresHandler(RelationHandler):
return bool(self.interface.service_password)
except AttributeError:
return False
class BasePeerHandler(RelationHandler):
def setup_event_handler(self):
"""Configure event handlers for peer relation."""
logger.debug("Setting up peer event handler")
peer_int = sunbeam_interfaces.OperatorPeers(
self.charm,
self.relation_name,
)
self.framework.observe(
peer_int.on.peers_data_changed,
self._on_peers_data_changed)
return peer_int
def _on_peers_data_changed(self, event) -> None:
self.callback_f(event)
@property
def ready(self) -> bool:
return True
def context(self):
try:
return self.interface.get_all_app_data()
except AttributeError:
return {}
def set_app_data(self, key, value):
self.interface.set_app_data(key, value)
def get_app_data(self, key):
self.interface.get_app_data(key)

View File

@ -155,6 +155,7 @@ TEMPLATE_CONTENTS = """
{{ amqp.transport_url }}
{{ amqp.hostname }}
{{ identity_service.service_password }}
{{ peers.foo }}
"""

View File

@ -102,8 +102,13 @@ class TestOSBaseOperatorAPICharm(test_utils.CharmTestCase):
self.harness.container_pebble_ready('my-service')
def test_write_config(self):
rel_id = self.harness.add_relation('peers', 'my-service')
self.harness.add_relation_unit(
rel_id,
'my-service/1')
self.harness.set_leader()
self.set_pebble_ready()
self.harness.charm.leader_set("foo", "bar")
test_utils.add_api_relations(self.harness)
expect_entries = [
'/bin/wsgi_admin',
@ -111,7 +116,8 @@ class TestOSBaseOperatorAPICharm(test_utils.CharmTestCase):
'true',
'rabbit://my-service:rabbit.pass@10.0.0.13:5672/openstack',
'rabbithost1.local',
'svcpass1']
'svcpass1',
'bar']
expect_string = '\n' + '\n'.join(expect_entries)
self.assertEqual(
self.container_calls['push']['/etc/my-service/my-service.conf'],