diff --git a/charms/cinder-k8s/fetch-libs.sh b/charms/cinder-k8s/fetch-libs.sh index 84894d7c..4b51dab5 100755 --- a/charms/cinder-k8s/fetch-libs.sh +++ b/charms/cinder-k8s/fetch-libs.sh @@ -1,9 +1,8 @@ #!/bin/bash echo "INFO: Fetching libs from charmhub." -charmcraft fetch-lib charms.nginx_ingress_integrator.v0.ingress charmcraft fetch-lib charms.data_platform_libs.v0.database_requires -charmcraft fetch-lib charms.sunbeam_keystone_operator.v0.identity_service -charmcraft fetch-lib charms.sunbeam_rabbitmq_operator.v0.amqp +charmcraft fetch-lib charms.keystone_k8s.v0.identity_service +charmcraft fetch-lib charms.rabbitmq_k8s.v0.rabbitmq charmcraft fetch-lib charms.observability_libs.v0.kubernetes_service_patch charmcraft fetch-lib charms.traefik_k8s.v1.ingress diff --git a/charms/cinder-k8s/lib/charms/sunbeam_cinder_operator/v0/storage_backend.py b/charms/cinder-k8s/lib/charms/cinder_k8s/v0/storage_backend.py similarity index 99% rename from charms/cinder-k8s/lib/charms/sunbeam_cinder_operator/v0/storage_backend.py rename to charms/cinder-k8s/lib/charms/cinder_k8s/v0/storage_backend.py index ed4fd0d9..8b1aa804 100644 --- a/charms/cinder-k8s/lib/charms/sunbeam_cinder_operator/v0/storage_backend.py +++ b/charms/cinder-k8s/lib/charms/cinder_k8s/v0/storage_backend.py @@ -20,14 +20,14 @@ Markdown is supported, following the CommonMark specification. """ # The unique Charmhub library identifier, never change it -LIBID = "570c8011bf5045d280452a1c27e18784" +LIBID = "68536ea2f06d40078ccbedd7095e141c" # 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 = 2 +LIBPATCH = 1 import json import logging diff --git a/charms/cinder-k8s/lib/charms/sunbeam_keystone_operator/v0/identity_service.py b/charms/cinder-k8s/lib/charms/keystone_k8s/v0/identity_service.py similarity index 98% rename from charms/cinder-k8s/lib/charms/sunbeam_keystone_operator/v0/identity_service.py rename to charms/cinder-k8s/lib/charms/keystone_k8s/v0/identity_service.py index e80e5a04..8f80a191 100644 --- a/charms/cinder-k8s/lib/charms/sunbeam_keystone_operator/v0/identity_service.py +++ b/charms/cinder-k8s/lib/charms/keystone_k8s/v0/identity_service.py @@ -90,7 +90,7 @@ from ops.model import Relation logger = logging.getLogger(__name__) # The unique Charmhub library identifier, never change it -LIBID = "6a7cb19b98314ecf916e3fcb02708608" +LIBID = "0fa7fe7236c14c6e9624acf232b9a3b0" # Increment this major API version when introducing breaking changes LIBAPI = 0 @@ -329,7 +329,9 @@ class IdentityServiceRequires(Object): if self.model.unit.is_leader(): logging.debug("Requesting service registration") app_data = self._identity_service_rel.data[self.charm.app] - app_data["service-endpoints"] = json.dumps(service_endpoints) + app_data["service-endpoints"] = json.dumps( + service_endpoints, sort_keys=True + ) app_data["region"] = region @@ -455,9 +457,13 @@ class IdentityServiceProvides(Object): admin_auth_url: str, public_auth_url: str): logging.debug("Setting identity_service connection information.") + _identity_service_rel = None for relation in self.framework.model.relations[relation_name]: if relation.id == relation_id: _identity_service_rel = relation + if not _identity_service_rel: + # Relation has disappeared so skip send of data + return app_data = _identity_service_rel.data[self.charm.app] app_data["api-version"] = api_version app_data["auth-host"] = auth_host diff --git a/charms/cinder-k8s/lib/charms/sunbeam_rabbitmq_operator/v0/amqp.py b/charms/cinder-k8s/lib/charms/rabbitmq_k8s/v0/rabbitmq.py similarity index 54% rename from charms/cinder-k8s/lib/charms/sunbeam_rabbitmq_operator/v0/amqp.py rename to charms/cinder-k8s/lib/charms/rabbitmq_k8s/v0/rabbitmq.py index 4c1540de..c7df2409 100644 --- a/charms/cinder-k8s/lib/charms/sunbeam_rabbitmq_operator/v0/amqp.py +++ b/charms/cinder-k8s/lib/charms/rabbitmq_k8s/v0/rabbitmq.py @@ -1,10 +1,9 @@ -"""AMQPProvides and Requires module. - +"""RabbitMQProvides and Requires module. This library contains the Requires and Provides classes for handling -the amqp interface. +the rabbitmq interface. -Import `AMQPRequires` in your charm, with the charm object and the +Import `RabbitMQRequires` in your charm, with the charm object and the relation name: - self - "amqp" @@ -21,13 +20,13 @@ Two events are also available to respond to: A basic example showing the usage of this relation follows: ``` -from charms.sunbeam_rabbitmq_operator.v0.amqp import AMQPRequires +from charms.rabbitmq_k8s.v0.rabbitmq import RabbitMQRequires -class AMQPClientCharm(CharmBase): +class RabbitMQClientCharm(CharmBase): def __init__(self, *args): super().__init__(*args) - # AMQP Requires - self.amqp = AMQPRequires( + # RabbitMQ Requires + self.amqp = RabbitMQRequires( self, "amqp", username="myusername", vhost="vhostname" @@ -40,45 +39,44 @@ class AMQPClientCharm(CharmBase): self.amqp.on.goneaway, self._on_amqp_goneaway) def _on_amqp_connected(self, event): - '''React to the AMQP connected event. + '''React to the RabbitMQ connected event. - This event happens when n AMQP relation is added to the + This event happens when n RabbitMQ relation is added to the model before credentials etc have been provided. ''' # Do something before the relation is complete pass def _on_amqp_ready(self, event): - '''React to the AMQP ready event. + '''React to the RabbitMQ ready event. - The AMQP interface will use the provided username and vhost for the + The RabbitMQ interface will use the provided username and vhost for the request to the rabbitmq server. ''' - # AMQP Relation is ready. Do something with the completed relation. + # RabbitMQ Relation is ready. Do something with the completed relation. pass def _on_amqp_goneaway(self, event): - '''React to the AMQP goneaway event. + '''React to the RabbitMQ goneaway event. - This event happens when an AMQP relation is removed. + This event happens when an RabbitMQ relation is removed. ''' - # AMQP Relation has goneaway. shutdown services or suchlike + # RabbitMQ Relation has goneaway. shutdown services or suchlike pass ``` """ # The unique Charmhub library identifier, never change it -LIBID = "ab1414b6baf044f099caf9c117f1a101" +LIBID = "45622352791142fd9cf87232e3bd6f2a" # 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 = 3 +LIBPATCH = 1 import logging -import requests from ops.framework import ( StoredState, @@ -95,39 +93,38 @@ from typing import List logger = logging.getLogger(__name__) -class AMQPConnectedEvent(EventBase): - """AMQP connected Event.""" +class RabbitMQConnectedEvent(EventBase): + """RabbitMQ connected Event.""" pass -class AMQPReadyEvent(EventBase): - """AMQP ready for use Event.""" +class RabbitMQReadyEvent(EventBase): + """RabbitMQ ready for use Event.""" pass -class AMQPGoneAwayEvent(EventBase): - """AMQP relation has gone-away Event""" +class RabbitMQGoneAwayEvent(EventBase): + """RabbitMQ relation has gone-away Event""" pass -class AMQPServerEvents(ObjectEvents): +class RabbitMQServerEvents(ObjectEvents): """Events class for `on`""" - connected = EventSource(AMQPConnectedEvent) - ready = EventSource(AMQPReadyEvent) - goneaway = EventSource(AMQPGoneAwayEvent) + connected = EventSource(RabbitMQConnectedEvent) + ready = EventSource(RabbitMQReadyEvent) + goneaway = EventSource(RabbitMQGoneAwayEvent) -class AMQPRequires(Object): +class RabbitMQRequires(Object): """ - AMQPRequires class + RabbitMQRequires class """ - on = AMQPServerEvents() - _stored = StoredState() + on = RabbitMQServerEvents() def __init__(self, charm, relation_name: str, username: str, vhost: str): super().__init__(charm, relation_name) @@ -153,94 +150,94 @@ class AMQPRequires(Object): ) def _on_amqp_relation_joined(self, event): - """AMQP relation joined.""" - logging.debug("RabbitMQAMQPRequires on_joined") + """RabbitMQ relation joined.""" + logging.debug("RabbitMQRabbitMQRequires on_joined") self.on.connected.emit() self.request_access(self.username, self.vhost) def _on_amqp_relation_changed(self, event): - """AMQP relation changed.""" - logging.debug("RabbitMQAMQPRequires on_changed") + """RabbitMQ relation changed.""" + logging.debug("RabbitMQRabbitMQRequires on_changed/departed") if self.password: self.on.ready.emit() def _on_amqp_relation_broken(self, event): - """AMQP relation broken.""" - logging.debug("RabbitMQAMQPRequires on_broken") + """RabbitMQ relation broken.""" + logging.debug("RabbitMQRabbitMQRequires on_broken") self.on.goneaway.emit() @property def _amqp_rel(self) -> Relation: - """The AMQP relation.""" + """The RabbitMQ relation.""" return self.framework.model.get_relation(self.relation_name) @property def password(self) -> str: - """Return the AMQP password from the server side of the relation.""" + """Return the RabbitMQ password from the server side of the relation.""" return self._amqp_rel.data[self._amqp_rel.app].get("password") @property def hostname(self) -> str: - """Return the hostname from the AMQP relation""" + """Return the hostname from the RabbitMQ relation""" return self._amqp_rel.data[self._amqp_rel.app].get("hostname") @property def ssl_port(self) -> str: - """Return the SSL port from the AMQP relation""" + """Return the SSL port from the RabbitMQ relation""" return self._amqp_rel.data[self._amqp_rel.app].get("ssl_port") @property def ssl_ca(self) -> str: - """Return the SSL port from the AMQP relation""" + """Return the SSL port from the RabbitMQ relation""" return self._amqp_rel.data[self._amqp_rel.app].get("ssl_ca") @property def hostnames(self) -> List[str]: - """Return a list of remote RMQ hosts from the AMQP relation""" + """Return a list of remote RMQ hosts from the RabbitMQ relation""" _hosts = [] for unit in self._amqp_rel.units: _hosts.append(self._amqp_rel.data[unit].get("ingress-address")) return _hosts def request_access(self, username: str, vhost: str) -> None: - """Request access to the AMQP server.""" + """Request access to the RabbitMQ server.""" if self.model.unit.is_leader(): - logging.debug("Requesting AMQP user and vhost") + logging.debug("Requesting RabbitMQ user and vhost") self._amqp_rel.data[self.charm.app]["username"] = username self._amqp_rel.data[self.charm.app]["vhost"] = vhost -class HasAMQPClientsEvent(EventBase): - """Has AMQPClients Event.""" +class HasRabbitMQClientsEvent(EventBase): + """Has RabbitMQClients Event.""" pass -class ReadyAMQPClientsEvent(EventBase): - """AMQPClients Ready Event.""" +class ReadyRabbitMQClientsEvent(EventBase): + """RabbitMQClients Ready Event.""" pass -class AMQPClientEvents(ObjectEvents): +class RabbitMQClientEvents(ObjectEvents): """Events class for `on`""" - has_amqp_clients = EventSource(HasAMQPClientsEvent) - ready_amqp_clients = EventSource(ReadyAMQPClientsEvent) + has_amqp_clients = EventSource(HasRabbitMQClientsEvent) + ready_amqp_clients = EventSource(ReadyRabbitMQClientsEvent) -class AMQPProvides(Object): +class RabbitMQProvides(Object): """ - AMQPProvides class + RabbitMQProvides class """ - on = AMQPClientEvents() - _stored = StoredState() + on = RabbitMQClientEvents() - def __init__(self, charm, relation_name): + def __init__(self, charm, relation_name, callback): super().__init__(charm, relation_name) self.charm = charm self.relation_name = relation_name + self.callback = callback self.framework.observe( self.charm.on[relation_name].relation_joined, self._on_amqp_relation_joined, @@ -255,60 +252,35 @@ class AMQPProvides(Object): ) def _on_amqp_relation_joined(self, event): - """Handle AMQP joined.""" - logging.debug("RabbitMQAMQPProvides on_joined") + """Handle RabbitMQ joined.""" + logging.debug("RabbitMQRabbitMQProvides on_joined data={}" + .format(event.relation.data[event.relation.app])) self.on.has_amqp_clients.emit() def _on_amqp_relation_changed(self, event): - """Handle AMQP changed.""" - logging.debug("RabbitMQAMQPProvides on_changed") + """Handle RabbitMQ changed.""" + logging.debug("RabbitMQRabbitMQProvides on_changed data={}" + .format(event.relation.data[event.relation.app])) # Validate data on the relation if self.username(event) and self.vhost(event): self.on.ready_amqp_clients.emit() if self.charm.unit.is_leader(): - self.set_amqp_credentials( - event, self.username(event), self.vhost(event) - ) + self.callback(event, self.username(event), self.vhost(event)) + else: + logging.warning("Received RabbitMQ changed event without the " + "expected keys ('username', 'vhost') in the " + "application data bag. Incompatible charm in " + "other end of relation?") def _on_amqp_relation_broken(self, event): - """Handle AMQP broken.""" - logging.debug("RabbitMQAMQPProvides on_departed") + """Handle RabbitMQ broken.""" + logging.debug("RabbitMQRabbitMQProvides on_departed") # TODO clear data on the relation def username(self, event): - """Return the AMQP username from the client side of the relation.""" + """Return the RabbitMQ username from the client side of the relation.""" return event.relation.data[event.relation.app].get("username") def vhost(self, event): - """Return the AMQP vhost from the client side of the relation.""" + """Return the RabbitMQ vhost from the client side of the relation.""" return event.relation.data[event.relation.app].get("vhost") - - def set_amqp_credentials(self, event, username, vhost): - """Set AMQP Credentials. - - :param event: The current event - :type EventsBase - :param username: The requested username - :type username: str - :param vhost: The requested vhost - :type vhost: str - :returns: None - :rtype: None - """ - # TODO: Can we move this into the charm code? - # TODO TLS Support. Existing interfaces set ssl_port and ssl_ca - logging.debug("Setting amqp connection information.") - try: - if not self.charm.does_vhost_exist(vhost): - self.charm.create_vhost(vhost) - password = self.charm.create_user(username) - self.charm.set_user_permissions(username, vhost) - event.relation.data[self.charm.app]["password"] = password - event.relation.data[self.charm.app][ - "hostname" - ] = self.charm.hostname - except requests.exceptions.ConnectionError as e: - logging.warning( - "Rabbitmq is not ready. Defering. Errno: {}".format(e.errno) - ) - event.defer() diff --git a/charms/cinder-k8s/src/charm.py b/charms/cinder-k8s/src/charm.py index 056fd073..449b5efb 100755 --- a/charms/cinder-k8s/src/charm.py +++ b/charms/cinder-k8s/src/charm.py @@ -17,7 +17,7 @@ import ops_sunbeam.core as sunbeam_core import ops_sunbeam.container_handlers as sunbeam_chandlers import ops_sunbeam.relation_handlers as sunbeam_rhandlers -import charms.sunbeam_cinder_operator.v0.storage_backend as sunbeam_storage_backend # noqa +import charms.cinder_k8s.v0.storage_backend as sunbeam_storage_backend # noqa logger = logging.getLogger(__name__)