diff --git a/charms/keystone-k8s/config.yaml b/charms/keystone-k8s/config.yaml index 90ef3ce5..6945a1bf 100644 --- a/charms/keystone-k8s/config.yaml +++ b/charms/keystone-k8s/config.yaml @@ -64,3 +64,7 @@ options: description: | Keystone identity backend, valid options are sql and pam + enable-telemetry-notifications: + type: boolean + default: False + description: Enable notifications to send to telemetry. diff --git a/charms/keystone-k8s/fetch-libs.sh b/charms/keystone-k8s/fetch-libs.sh index 00592333..62b2328d 100755 --- a/charms/keystone-k8s/fetch-libs.sh +++ b/charms/keystone-k8s/fetch-libs.sh @@ -5,5 +5,5 @@ 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.v1.identity_service #charmcraft fetch-lib charms.sunbeam_keystone_operator.v0.identity_credentials -charmcraft fetch-lib charms.sunbeam_rabbitmq_operator.v0.amqp +charmcraft fetch-lib charms.rabbitmq_k8s.v0.rabbitmq charmcraft fetch-lib charms.traefik_k8s.v1.ingress diff --git a/charms/keystone-k8s/lib/charms/sunbeam_rabbitmq_operator/v0/amqp.py b/charms/keystone-k8s/lib/charms/rabbitmq_k8s/v0/rabbitmq.py similarity index 62% rename from charms/keystone-k8s/lib/charms/sunbeam_rabbitmq_operator/v0/amqp.py rename to charms/keystone-k8s/lib/charms/rabbitmq_k8s/v0/rabbitmq.py index 84b0b5a2..c7df2409 100644 --- a/charms/keystone-k8s/lib/charms/sunbeam_rabbitmq_operator/v0/amqp.py +++ b/charms/keystone-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,42 +39,42 @@ 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 = 4 +LIBPATCH = 1 import logging @@ -94,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) @@ -152,89 +150,88 @@ 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/departed") + """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, callback): super().__init__(charm, relation_name) @@ -255,35 +252,35 @@ class AMQPProvides(Object): ) def _on_amqp_relation_joined(self, event): - """Handle AMQP joined.""" - logging.debug("RabbitMQAMQPProvides on_joined data={}" - .format(event.relation.data)) + """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 data={}" - .format(event.relation.data)) + """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.callback(event, self.username(event), self.vhost(event)) else: - logging.warning("Received AMQP changed event without the " + 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") diff --git a/charms/keystone-k8s/metadata.yaml b/charms/keystone-k8s/metadata.yaml index 9674fea4..ea4ff9e3 100644 --- a/charms/keystone-k8s/metadata.yaml +++ b/charms/keystone-k8s/metadata.yaml @@ -41,6 +41,9 @@ requires: ingress-public: interface: ingress limit: 1 + amqp: + interface: rabbitmq + optional: true peers: peers: diff --git a/charms/keystone-k8s/src/charm.py b/charms/keystone-k8s/src/charm.py index d309d4cc..ab0787ea 100755 --- a/charms/keystone-k8s/src/charm.py +++ b/charms/keystone-k8s/src/charm.py @@ -729,12 +729,14 @@ export OS_AUTH_VERSION=3 @property def config_contexts(self) -> List[sunbeam_contexts.ConfigContext]: """Configuration adapters for the operator.""" - return [ - KeystoneConfigAdapter(self, "ks_config"), - KeystoneLoggingAdapter(self, "ks_logging"), - sunbeam_contexts.WSGIWorkerConfigContext(self, "wsgi_config"), - sunbeam_contexts.CharmConfigContext(self, "options"), - ] + contexts = super().config_contexts + contexts.extend( + [ + KeystoneConfigAdapter(self, "ks_config"), + KeystoneLoggingAdapter(self, "ks_logging"), + ] + ) + return contexts @property def container_configs(self): diff --git a/charms/keystone-k8s/src/templates/keystone.conf.j2 b/charms/keystone-k8s/src/templates/keystone.conf.j2 index 86bdbe67..044ba06b 100644 --- a/charms/keystone-k8s/src/templates/keystone.conf.j2 +++ b/charms/keystone-k8s/src/templates/keystone.conf.j2 @@ -7,6 +7,10 @@ log_config_append = /etc/keystone/logging.conf debug = {{ options.debug }} +{% if amqp -%} +transport_url = {{ amqp.transport_url }} +{%- endif %} + [identity] driver = {{ ks_config.identity_backend }} {% if ks_config.default_domain_id -%} @@ -106,3 +110,5 @@ admin_project_name = admin # This goes in the section above, selectively # Bug #1819134 max_request_body_size = 114688 + +{% include "parts/section-oslo-notifications" %} diff --git a/charms/keystone-k8s/src/templates/parts/section-oslo-notifications b/charms/keystone-k8s/src/templates/parts/section-oslo-notifications new file mode 100644 index 00000000..ce559feb --- /dev/null +++ b/charms/keystone-k8s/src/templates/parts/section-oslo-notifications @@ -0,0 +1,4 @@ +{% if options.enable_telemetry_notifications -%} +[oslo_messaging_notifications] +driver = messagingv2 +{%- endif %} diff --git a/charms/keystone-k8s/tests/bundles/smoke.yaml b/charms/keystone-k8s/tests/bundles/smoke.yaml index dcc53350..044f0762 100644 --- a/charms/keystone-k8s/tests/bundles/smoke.yaml +++ b/charms/keystone-k8s/tests/bundles/smoke.yaml @@ -54,6 +54,9 @@ relations: - - traefik:ingress - glance:ingress-public +- - rabbitmq:amqp + - keystone:amqp + - - mysql:database - keystone:database