Add library ceilometer-service

Add new library ceilometer-service.
Update ceilometer charm to handle the interface provider events.

Change-Id: Ibe49fa91dbf224dae98f6258fbd8ec22c7ccd3be
This commit is contained in:
Hemanth Nakkina
2023-08-30 16:48:21 +05:30
parent e3d77b77be
commit ed16861860
3 changed files with 309 additions and 4 deletions

View File

@@ -0,0 +1,224 @@
"""CeilometerServiceProvides and Requires module.
This library contains the Requires and Provides classes for handling
the ceilometer_service interface.
Import `CeilometerServiceRequires` in your charm, with the charm object and the
relation name:
- self
- "ceilometer_service"
Two events are also available to respond to:
- config_changed
- goneaway
A basic example showing the usage of this relation follows:
```
from charms.ceilometer_k8s.v0.ceilometer_service import (
CeilometerServiceRequires
)
class CeilometerServiceClientCharm(CharmBase):
def __init__(self, *args):
super().__init__(*args)
# CeilometerService Requires
self.ceilometer_service = CeilometerServiceRequires(
self, "ceilometer_service",
)
self.framework.observe(
self.ceilometer_service.on.config_changed,
self._on_ceilometer_service_config_changed
)
self.framework.observe(
self.ceilometer_service.on.goneaway,
self._on_ceiometer_service_goneaway
)
def _on_ceilometer_service_config_changed(self, event):
'''React to the Ceilometer service config changed event.
This event happens when CeilometerService relation is added to the
model and relation data is changed.
'''
# Do something with the configuration provided by relation.
pass
def _on_ceilometer_service_goneaway(self, event):
'''React to the CeilometerService goneaway event.
This event happens when CeilometerService relation is removed.
'''
# CeilometerService Relation has goneaway.
pass
```
"""
import logging
from typing import (
Optional,
)
from ops.charm import (
CharmBase,
RelationBrokenEvent,
RelationChangedEvent,
RelationEvent,
)
from ops.framework import (
EventSource,
Object,
ObjectEvents,
)
from ops.model import (
Relation,
)
logger = logging.getLogger(__name__)
# The unique Charmhub library identifier, never change it
LIBID = "fcbb94e7a18740729eaf9e2c3b90017f"
# Increment this major API version when introducing breaking changes
LIBAPI = 0
# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1
class CeilometerConfigRequestEvent(RelationEvent):
"""CeilometerConfigRequest Event."""
pass
class CeilometerServiceProviderEvents(ObjectEvents):
"""Events class for `on`."""
config_request = EventSource(CeilometerConfigRequestEvent)
class CeilometerServiceProvides(Object):
"""CeilometerServiceProvides class."""
on = CeilometerServiceProviderEvents()
def __init__(self, charm: CharmBase, relation_name: str):
super().__init__(charm, relation_name)
self.charm = charm
self.relation_name = relation_name
self.framework.observe(
self.charm.on[relation_name].relation_changed,
self._on_ceilometer_service_relation_changed,
)
def _on_ceilometer_service_relation_changed(
self, event: RelationChangedEvent
):
"""Handle CeilometerService relation changed."""
logging.debug("CeilometerService relation changed")
self.on.config_request.emit(event.relation)
def set_config(
self, relation: Optional[Relation], telemetry_secret: str
) -> None:
"""Set ceilometer configuration on the relation."""
if not self.charm.unit.is_leader():
logging.debug("Not a leader unit, skipping set config")
return
# If relation is not provided send config to all the related
# applications. This happens usually when config data is
# updated by provider and wants to send the data to all
# related applications
if relation is None:
logging.debug(
"Sending config to all related applications of relation"
f"{self.relation_name}"
)
for relation in self.framework.model.relations[self.relation_name]:
relation.data[self.charm.app][
"telemetry-secret"
] = telemetry_secret
else:
logging.debug(
f"Sending config on relation {relation.app.name} "
f"{relation.name}/{relation.id}"
)
relation.data[self.charm.app][
"telemetry-secret"
] = telemetry_secret
class CeilometerConfigChangedEvent(RelationEvent):
"""CeilometerConfigChanged Event."""
pass
class CeilometerServiceGoneAwayEvent(RelationEvent):
"""CeilometerServiceGoneAway Event."""
pass
class CeilometerServiceRequirerEvents(ObjectEvents):
"""Events class for `on`."""
config_changed = EventSource(CeilometerConfigChangedEvent)
goneaway = EventSource(CeilometerServiceGoneAwayEvent)
class CeilometerServiceRequires(Object):
"""CeilometerServiceRequires class."""
on = CeilometerServiceRequirerEvents()
def __init__(self, charm: CharmBase, relation_name: str):
super().__init__(charm, relation_name)
self.charm = charm
self.relation_name = relation_name
self.framework.observe(
self.charm.on[relation_name].relation_changed,
self._on_ceilometer_service_relation_changed,
)
self.framework.observe(
self.charm.on[relation_name].relation_broken,
self._on_ceilometer_service_relation_broken,
)
def _on_ceilometer_service_relation_changed(
self, event: RelationChangedEvent
):
"""Handle CeilometerService relation changed."""
logging.debug("CeilometerService config data changed")
self.on.config_changed.emit(event.relation)
def _on_ceilometer_service_relation_broken(
self, event: RelationBrokenEvent
):
"""Handle CeilometerService relation changed."""
logging.debug("CeilometerService on_broken")
self.on.goneaway.emit(event.relation)
@property
def _ceilometer_service_rel(self) -> Optional[Relation]:
"""The ceilometer service relation."""
return self.framework.model.get_relation(self.relation_name)
def get_remote_app_data(self, key: str) -> Optional[str]:
"""Return the value for the given key from remote app data."""
if self._ceilometer_service_rel:
data = self._ceilometer_service_rel.data[
self._ceilometer_service_rel.app
]
return data.get(key)
return None
@property
def telemetry_secret(self) -> Optional[str]:
"""Return the telemetry_secret."""
return self.get_remote_app_data("telemetry-secret")

View File

@@ -34,6 +34,10 @@ resources:
description: OCI image for OpenStack ceilometer
upstream-source: ghcr.io/openstack-snaps/ceilometer-consolidated:2023.1
provides:
ceilometer-service:
interface: ceilometer
requires:
amqp:
interface: rabbitmq

View File

@@ -21,15 +21,22 @@ This charm provide Ceilometer services as part of an OpenStack deployment
import logging
import uuid
from typing import (
Callable,
List,
)
import ops.framework
import ops_sunbeam.charm as sunbeam_charm
import ops_sunbeam.container_handlers as container_handlers
import ops_sunbeam.container_handlers as sunbeam_chandlers
import ops_sunbeam.core as sunbeam_core
import ops_sunbeam.relation_handlers as sunbeam_rhandlers
from charms.ceilometer_k8s.v0.ceilometer_service import (
CeilometerConfigRequestEvent,
CeilometerServiceProvides,
)
from ops.charm import (
ActionEvent,
CharmBase,
)
from ops.main import (
main,
@@ -41,7 +48,41 @@ CEILOMETER_CENTRAL_CONTAINER = "ceilometer-central"
CEILOMETER_NOTIFICATION_CONTAINER = "ceilometer-notification"
class CeilometerCentralPebbleHandler(container_handlers.ServicePebbleHandler):
class CeilometerServiceProvidesHandler(sunbeam_rhandlers.RelationHandler):
"""Handler for ceilometer service relation."""
def __init__(
self,
charm: CharmBase,
relation_name: str,
callback_f: Callable,
):
super().__init__(charm, relation_name, callback_f)
def setup_event_handler(self):
"""Configure event handlers for an Ceilometer service relation."""
logger.debug("Setting up Ceilometer service event handler")
svc = CeilometerServiceProvides(
self.charm,
self.relation_name,
)
self.framework.observe(
svc.on.config_request,
self._on_config_request,
)
return svc
def _on_config_request(self, event: CeilometerConfigRequestEvent) -> None:
"""Handle Config request event."""
self.callback_f(event)
@property
def ready(self) -> bool:
"""Report if relation is ready."""
return True
class CeilometerCentralPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
"""Pebble handler for ceilometer-central service."""
def get_layer(self) -> dict:
@@ -77,7 +118,7 @@ class CeilometerCentralPebbleHandler(container_handlers.ServicePebbleHandler):
class CeilometerNotificationPebbleHandler(
container_handlers.ServicePebbleHandler
sunbeam_chandlers.ServicePebbleHandler
):
"""Pebble handler for ceilometer-notification service."""
@@ -163,6 +204,7 @@ class CeilometerOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
if self.unit.is_leader():
logger.debug("Creating metering secret")
self.set_shared_meteringsecret()
self.set_config_on_update()
else:
logger.debug("Metadata secret not ready")
return
@@ -191,7 +233,7 @@ class CeilometerOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
]
return _cconfigs
def get_pebble_handlers(self) -> List[container_handlers.PebbleHandler]:
def get_pebble_handlers(self) -> List[sunbeam_chandlers.PebbleHandler]:
"""Pebble handlers for the operator."""
return [
CeilometerCentralPebbleHandler(
@@ -212,6 +254,41 @@ class CeilometerOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
),
]
def get_relation_handlers(
self, handlers: List[sunbeam_rhandlers.RelationHandler] = None
) -> List[sunbeam_rhandlers.RelationHandler]:
"""Relation handlers for the service."""
handlers = handlers or []
if self.can_add_handler("ceilometer-service", handlers):
self.config_svc = CeilometerServiceProvidesHandler(
self,
"ceilometer-service",
self.set_config_from_event,
)
handlers.append(self.config_svc)
return super().get_relation_handlers(handlers)
def set_config_from_event(self, event: ops.framework.EventBase) -> None:
"""Set config in relation data."""
telemetry_secret = self.get_shared_meteringsecret()
if telemetry_secret:
self.config_svc.interface.set_config(
relation=event.relation, telemetry_secret=telemetry_secret
)
else:
logging.debug("Telemetry secret not yet set, not sending config")
def set_config_on_update(self) -> None:
"""Set config on relation on update of local data."""
telemetry_secret = self.get_shared_meteringsecret()
if telemetry_secret:
self.config_svc.interface.set_config(
relation=None, telemetry_secret=telemetry_secret
)
else:
logging.debug("Telemetry secret not yet set, not sending config")
def _ceilometer_upgrade_action(self, event: ActionEvent) -> None:
"""Run ceilometer-upgrade.