Refresh libraries for new publication points
Ensure that all libraries are sourced from k8s operators rather than the sunbeam prototypes. Drive-by fix for link to config.yaml in tests folder. Change-Id: I32919b13eb5e974af10140113829146516acc6d8
This commit is contained in:
parent
61784f64b9
commit
2188416b10
@ -1,9 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "INFO: Fetching libs from charmhub."
|
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.data_platform_libs.v0.database_requires
|
||||||
charmcraft fetch-lib charms.sunbeam_keystone_operator.v0.identity_service
|
charmcraft fetch-lib charms.keystone_k8s.v0.identity_service
|
||||||
charmcraft fetch-lib charms.sunbeam_rabbitmq_operator.v0.amqp
|
charmcraft fetch-lib charms.rabbitmq_k8s.v0.rabbitmq
|
||||||
charmcraft fetch-lib charms.observability_libs.v0.kubernetes_service_patch
|
charmcraft fetch-lib charms.observability_libs.v0.kubernetes_service_patch
|
||||||
charmcraft fetch-lib charms.traefik_k8s.v1.ingress
|
charmcraft fetch-lib charms.traefik_k8s.v1.ingress
|
||||||
|
@ -90,7 +90,7 @@ from ops.model import Relation
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# The unique Charmhub library identifier, never change it
|
# The unique Charmhub library identifier, never change it
|
||||||
LIBID = "6a7cb19b98314ecf916e3fcb02708608"
|
LIBID = "0fa7fe7236c14c6e9624acf232b9a3b0"
|
||||||
|
|
||||||
# Increment this major API version when introducing breaking changes
|
# Increment this major API version when introducing breaking changes
|
||||||
LIBAPI = 0
|
LIBAPI = 0
|
||||||
@ -329,7 +329,9 @@ class IdentityServiceRequires(Object):
|
|||||||
if self.model.unit.is_leader():
|
if self.model.unit.is_leader():
|
||||||
logging.debug("Requesting service registration")
|
logging.debug("Requesting service registration")
|
||||||
app_data = self._identity_service_rel.data[self.charm.app]
|
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
|
app_data["region"] = region
|
||||||
|
|
||||||
|
|
||||||
@ -455,9 +457,13 @@ class IdentityServiceProvides(Object):
|
|||||||
admin_auth_url: str,
|
admin_auth_url: str,
|
||||||
public_auth_url: str):
|
public_auth_url: str):
|
||||||
logging.debug("Setting identity_service connection information.")
|
logging.debug("Setting identity_service connection information.")
|
||||||
|
_identity_service_rel = None
|
||||||
for relation in self.framework.model.relations[relation_name]:
|
for relation in self.framework.model.relations[relation_name]:
|
||||||
if relation.id == relation_id:
|
if relation.id == relation_id:
|
||||||
_identity_service_rel = relation
|
_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 = _identity_service_rel.data[self.charm.app]
|
||||||
app_data["api-version"] = api_version
|
app_data["api-version"] = api_version
|
||||||
app_data["auth-host"] = auth_host
|
app_data["auth-host"] = auth_host
|
@ -1,211 +0,0 @@
|
|||||||
"""Library for the ingress relation.
|
|
||||||
|
|
||||||
This library contains the Requires and Provides classes for handling
|
|
||||||
the ingress interface.
|
|
||||||
|
|
||||||
Import `IngressRequires` in your charm, with two required options:
|
|
||||||
- "self" (the charm itself)
|
|
||||||
- config_dict
|
|
||||||
|
|
||||||
`config_dict` accepts the following keys:
|
|
||||||
- service-hostname (required)
|
|
||||||
- service-name (required)
|
|
||||||
- service-port (required)
|
|
||||||
- additional-hostnames
|
|
||||||
- limit-rps
|
|
||||||
- limit-whitelist
|
|
||||||
- max-body-size
|
|
||||||
- path-routes
|
|
||||||
- retry-errors
|
|
||||||
- rewrite-enabled
|
|
||||||
- rewrite-target
|
|
||||||
- service-namespace
|
|
||||||
- session-cookie-max-age
|
|
||||||
- tls-secret-name
|
|
||||||
|
|
||||||
See [the config section](https://charmhub.io/nginx-ingress-integrator/configure) for descriptions
|
|
||||||
of each, along with the required type.
|
|
||||||
|
|
||||||
As an example, add the following to `src/charm.py`:
|
|
||||||
```
|
|
||||||
from charms.nginx_ingress_integrator.v0.ingress import IngressRequires
|
|
||||||
|
|
||||||
# In your charm's `__init__` method.
|
|
||||||
self.ingress = IngressRequires(self, {"service-hostname": self.config["external_hostname"],
|
|
||||||
"service-name": self.app.name,
|
|
||||||
"service-port": 80})
|
|
||||||
|
|
||||||
# In your charm's `config-changed` handler.
|
|
||||||
self.ingress.update_config({"service-hostname": self.config["external_hostname"]})
|
|
||||||
```
|
|
||||||
And then add the following to `metadata.yaml`:
|
|
||||||
```
|
|
||||||
requires:
|
|
||||||
ingress:
|
|
||||||
interface: ingress
|
|
||||||
```
|
|
||||||
You _must_ register the IngressRequires class as part of the `__init__` method
|
|
||||||
rather than, for instance, a config-changed event handler. This is because
|
|
||||||
doing so won't get the current relation changed event, because it wasn't
|
|
||||||
registered to handle the event (because it wasn't created in `__init__` when
|
|
||||||
the event was fired).
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from ops.charm import CharmEvents
|
|
||||||
from ops.framework import EventBase, EventSource, Object
|
|
||||||
from ops.model import BlockedStatus
|
|
||||||
|
|
||||||
# The unique Charmhub library identifier, never change it
|
|
||||||
LIBID = "db0af4367506491c91663468fb5caa4c"
|
|
||||||
|
|
||||||
# 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 = 9
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
REQUIRED_INGRESS_RELATION_FIELDS = {
|
|
||||||
"service-hostname",
|
|
||||||
"service-name",
|
|
||||||
"service-port",
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTIONAL_INGRESS_RELATION_FIELDS = {
|
|
||||||
"additional-hostnames",
|
|
||||||
"limit-rps",
|
|
||||||
"limit-whitelist",
|
|
||||||
"max-body-size",
|
|
||||||
"retry-errors",
|
|
||||||
"rewrite-target",
|
|
||||||
"rewrite-enabled",
|
|
||||||
"service-namespace",
|
|
||||||
"session-cookie-max-age",
|
|
||||||
"tls-secret-name",
|
|
||||||
"path-routes",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class IngressAvailableEvent(EventBase):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class IngressCharmEvents(CharmEvents):
|
|
||||||
"""Custom charm events."""
|
|
||||||
|
|
||||||
ingress_available = EventSource(IngressAvailableEvent)
|
|
||||||
|
|
||||||
|
|
||||||
class IngressRequires(Object):
|
|
||||||
"""This class defines the functionality for the 'requires' side of the 'ingress' relation.
|
|
||||||
|
|
||||||
Hook events observed:
|
|
||||||
- relation-changed
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, charm, config_dict):
|
|
||||||
super().__init__(charm, "ingress")
|
|
||||||
|
|
||||||
self.framework.observe(charm.on["ingress"].relation_changed, self._on_relation_changed)
|
|
||||||
|
|
||||||
self.config_dict = config_dict
|
|
||||||
|
|
||||||
def _config_dict_errors(self, update_only=False):
|
|
||||||
"""Check our config dict for errors."""
|
|
||||||
blocked_message = "Error in ingress relation, check `juju debug-log`"
|
|
||||||
unknown = [
|
|
||||||
x
|
|
||||||
for x in self.config_dict
|
|
||||||
if x not in REQUIRED_INGRESS_RELATION_FIELDS | OPTIONAL_INGRESS_RELATION_FIELDS
|
|
||||||
]
|
|
||||||
if unknown:
|
|
||||||
logger.error(
|
|
||||||
"Ingress relation error, unknown key(s) in config dictionary found: %s",
|
|
||||||
", ".join(unknown),
|
|
||||||
)
|
|
||||||
self.model.unit.status = BlockedStatus(blocked_message)
|
|
||||||
return True
|
|
||||||
if not update_only:
|
|
||||||
missing = [x for x in REQUIRED_INGRESS_RELATION_FIELDS if x not in self.config_dict]
|
|
||||||
if missing:
|
|
||||||
logger.error(
|
|
||||||
"Ingress relation error, missing required key(s) in config dictionary: %s",
|
|
||||||
", ".join(missing),
|
|
||||||
)
|
|
||||||
self.model.unit.status = BlockedStatus(blocked_message)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _on_relation_changed(self, event):
|
|
||||||
"""Handle the relation-changed event."""
|
|
||||||
# `self.unit` isn't available here, so use `self.model.unit`.
|
|
||||||
if self.model.unit.is_leader():
|
|
||||||
if self._config_dict_errors():
|
|
||||||
return
|
|
||||||
for key in self.config_dict:
|
|
||||||
event.relation.data[self.model.app][key] = str(self.config_dict[key])
|
|
||||||
|
|
||||||
def update_config(self, config_dict):
|
|
||||||
"""Allow for updates to relation."""
|
|
||||||
if self.model.unit.is_leader():
|
|
||||||
self.config_dict = config_dict
|
|
||||||
if self._config_dict_errors(update_only=True):
|
|
||||||
return
|
|
||||||
relation = self.model.get_relation("ingress")
|
|
||||||
if relation:
|
|
||||||
for key in self.config_dict:
|
|
||||||
relation.data[self.model.app][key] = str(self.config_dict[key])
|
|
||||||
|
|
||||||
|
|
||||||
class IngressProvides(Object):
|
|
||||||
"""This class defines the functionality for the 'provides' side of the 'ingress' relation.
|
|
||||||
|
|
||||||
Hook events observed:
|
|
||||||
- relation-changed
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, charm):
|
|
||||||
super().__init__(charm, "ingress")
|
|
||||||
# Observe the relation-changed hook event and bind
|
|
||||||
# self.on_relation_changed() to handle the event.
|
|
||||||
self.framework.observe(charm.on["ingress"].relation_changed, self._on_relation_changed)
|
|
||||||
self.charm = charm
|
|
||||||
|
|
||||||
def _on_relation_changed(self, event):
|
|
||||||
"""Handle a change to the ingress relation.
|
|
||||||
|
|
||||||
Confirm we have the fields we expect to receive."""
|
|
||||||
# `self.unit` isn't available here, so use `self.model.unit`.
|
|
||||||
if not self.model.unit.is_leader():
|
|
||||||
return
|
|
||||||
|
|
||||||
ingress_data = {
|
|
||||||
field: event.relation.data[event.app].get(field)
|
|
||||||
for field in REQUIRED_INGRESS_RELATION_FIELDS | OPTIONAL_INGRESS_RELATION_FIELDS
|
|
||||||
}
|
|
||||||
|
|
||||||
missing_fields = sorted(
|
|
||||||
[
|
|
||||||
field
|
|
||||||
for field in REQUIRED_INGRESS_RELATION_FIELDS
|
|
||||||
if ingress_data.get(field) is None
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
if missing_fields:
|
|
||||||
logger.error(
|
|
||||||
"Missing required data fields for ingress relation: {}".format(
|
|
||||||
", ".join(missing_fields)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.model.unit.status = BlockedStatus(
|
|
||||||
"Missing fields for ingress: {}".format(", ".join(missing_fields))
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create an event that our charm can use to decide it's okay to
|
|
||||||
# configure the ingress.
|
|
||||||
self.charm.on.ingress_available.emit()
|
|
@ -1,10 +1,9 @@
|
|||||||
"""AMQPProvides and Requires module.
|
"""RabbitMQProvides and Requires module.
|
||||||
|
|
||||||
|
|
||||||
This library contains the Requires and Provides classes for handling
|
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:
|
relation name:
|
||||||
- self
|
- self
|
||||||
- "amqp"
|
- "amqp"
|
||||||
@ -21,13 +20,13 @@ Two events are also available to respond to:
|
|||||||
A basic example showing the usage of this relation follows:
|
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):
|
def __init__(self, *args):
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
# AMQP Requires
|
# RabbitMQ Requires
|
||||||
self.amqp = AMQPRequires(
|
self.amqp = RabbitMQRequires(
|
||||||
self, "amqp",
|
self, "amqp",
|
||||||
username="myusername",
|
username="myusername",
|
||||||
vhost="vhostname"
|
vhost="vhostname"
|
||||||
@ -40,45 +39,44 @@ class AMQPClientCharm(CharmBase):
|
|||||||
self.amqp.on.goneaway, self._on_amqp_goneaway)
|
self.amqp.on.goneaway, self._on_amqp_goneaway)
|
||||||
|
|
||||||
def _on_amqp_connected(self, event):
|
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.
|
model before credentials etc have been provided.
|
||||||
'''
|
'''
|
||||||
# Do something before the relation is complete
|
# Do something before the relation is complete
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _on_amqp_ready(self, event):
|
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.
|
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
|
pass
|
||||||
|
|
||||||
def _on_amqp_goneaway(self, event):
|
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
|
pass
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The unique Charmhub library identifier, never change it
|
# The unique Charmhub library identifier, never change it
|
||||||
LIBID = "ab1414b6baf044f099caf9c117f1a101"
|
LIBID = "45622352791142fd9cf87232e3bd6f2a"
|
||||||
|
|
||||||
# Increment this major API version when introducing breaking changes
|
# Increment this major API version when introducing breaking changes
|
||||||
LIBAPI = 0
|
LIBAPI = 0
|
||||||
|
|
||||||
# Increment this PATCH version before using `charmcraft publish-lib` or reset
|
# Increment this PATCH version before using `charmcraft publish-lib` or reset
|
||||||
# to 0 if you are raising the major API version
|
# to 0 if you are raising the major API version
|
||||||
LIBPATCH = 3
|
LIBPATCH = 1
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import requests
|
|
||||||
|
|
||||||
from ops.framework import (
|
from ops.framework import (
|
||||||
StoredState,
|
StoredState,
|
||||||
@ -95,39 +93,38 @@ from typing import List
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AMQPConnectedEvent(EventBase):
|
class RabbitMQConnectedEvent(EventBase):
|
||||||
"""AMQP connected Event."""
|
"""RabbitMQ connected Event."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AMQPReadyEvent(EventBase):
|
class RabbitMQReadyEvent(EventBase):
|
||||||
"""AMQP ready for use Event."""
|
"""RabbitMQ ready for use Event."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AMQPGoneAwayEvent(EventBase):
|
class RabbitMQGoneAwayEvent(EventBase):
|
||||||
"""AMQP relation has gone-away Event"""
|
"""RabbitMQ relation has gone-away Event"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AMQPServerEvents(ObjectEvents):
|
class RabbitMQServerEvents(ObjectEvents):
|
||||||
"""Events class for `on`"""
|
"""Events class for `on`"""
|
||||||
|
|
||||||
connected = EventSource(AMQPConnectedEvent)
|
connected = EventSource(RabbitMQConnectedEvent)
|
||||||
ready = EventSource(AMQPReadyEvent)
|
ready = EventSource(RabbitMQReadyEvent)
|
||||||
goneaway = EventSource(AMQPGoneAwayEvent)
|
goneaway = EventSource(RabbitMQGoneAwayEvent)
|
||||||
|
|
||||||
|
|
||||||
class AMQPRequires(Object):
|
class RabbitMQRequires(Object):
|
||||||
"""
|
"""
|
||||||
AMQPRequires class
|
RabbitMQRequires class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
on = AMQPServerEvents()
|
on = RabbitMQServerEvents()
|
||||||
_stored = StoredState()
|
|
||||||
|
|
||||||
def __init__(self, charm, relation_name: str, username: str, vhost: str):
|
def __init__(self, charm, relation_name: str, username: str, vhost: str):
|
||||||
super().__init__(charm, relation_name)
|
super().__init__(charm, relation_name)
|
||||||
@ -153,94 +150,94 @@ class AMQPRequires(Object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _on_amqp_relation_joined(self, event):
|
def _on_amqp_relation_joined(self, event):
|
||||||
"""AMQP relation joined."""
|
"""RabbitMQ relation joined."""
|
||||||
logging.debug("RabbitMQAMQPRequires on_joined")
|
logging.debug("RabbitMQRabbitMQRequires on_joined")
|
||||||
self.on.connected.emit()
|
self.on.connected.emit()
|
||||||
self.request_access(self.username, self.vhost)
|
self.request_access(self.username, self.vhost)
|
||||||
|
|
||||||
def _on_amqp_relation_changed(self, event):
|
def _on_amqp_relation_changed(self, event):
|
||||||
"""AMQP relation changed."""
|
"""RabbitMQ relation changed."""
|
||||||
logging.debug("RabbitMQAMQPRequires on_changed")
|
logging.debug("RabbitMQRabbitMQRequires on_changed/departed")
|
||||||
if self.password:
|
if self.password:
|
||||||
self.on.ready.emit()
|
self.on.ready.emit()
|
||||||
|
|
||||||
def _on_amqp_relation_broken(self, event):
|
def _on_amqp_relation_broken(self, event):
|
||||||
"""AMQP relation broken."""
|
"""RabbitMQ relation broken."""
|
||||||
logging.debug("RabbitMQAMQPRequires on_broken")
|
logging.debug("RabbitMQRabbitMQRequires on_broken")
|
||||||
self.on.goneaway.emit()
|
self.on.goneaway.emit()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _amqp_rel(self) -> Relation:
|
def _amqp_rel(self) -> Relation:
|
||||||
"""The AMQP relation."""
|
"""The RabbitMQ relation."""
|
||||||
return self.framework.model.get_relation(self.relation_name)
|
return self.framework.model.get_relation(self.relation_name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def password(self) -> str:
|
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")
|
return self._amqp_rel.data[self._amqp_rel.app].get("password")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hostname(self) -> str:
|
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")
|
return self._amqp_rel.data[self._amqp_rel.app].get("hostname")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ssl_port(self) -> str:
|
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")
|
return self._amqp_rel.data[self._amqp_rel.app].get("ssl_port")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ssl_ca(self) -> str:
|
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")
|
return self._amqp_rel.data[self._amqp_rel.app].get("ssl_ca")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hostnames(self) -> List[str]:
|
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 = []
|
_hosts = []
|
||||||
for unit in self._amqp_rel.units:
|
for unit in self._amqp_rel.units:
|
||||||
_hosts.append(self._amqp_rel.data[unit].get("ingress-address"))
|
_hosts.append(self._amqp_rel.data[unit].get("ingress-address"))
|
||||||
return _hosts
|
return _hosts
|
||||||
|
|
||||||
def request_access(self, username: str, vhost: str) -> None:
|
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():
|
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]["username"] = username
|
||||||
self._amqp_rel.data[self.charm.app]["vhost"] = vhost
|
self._amqp_rel.data[self.charm.app]["vhost"] = vhost
|
||||||
|
|
||||||
|
|
||||||
class HasAMQPClientsEvent(EventBase):
|
class HasRabbitMQClientsEvent(EventBase):
|
||||||
"""Has AMQPClients Event."""
|
"""Has RabbitMQClients Event."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ReadyAMQPClientsEvent(EventBase):
|
class ReadyRabbitMQClientsEvent(EventBase):
|
||||||
"""AMQPClients Ready Event."""
|
"""RabbitMQClients Ready Event."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AMQPClientEvents(ObjectEvents):
|
class RabbitMQClientEvents(ObjectEvents):
|
||||||
"""Events class for `on`"""
|
"""Events class for `on`"""
|
||||||
|
|
||||||
has_amqp_clients = EventSource(HasAMQPClientsEvent)
|
has_amqp_clients = EventSource(HasRabbitMQClientsEvent)
|
||||||
ready_amqp_clients = EventSource(ReadyAMQPClientsEvent)
|
ready_amqp_clients = EventSource(ReadyRabbitMQClientsEvent)
|
||||||
|
|
||||||
|
|
||||||
class AMQPProvides(Object):
|
class RabbitMQProvides(Object):
|
||||||
"""
|
"""
|
||||||
AMQPProvides class
|
RabbitMQProvides class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
on = AMQPClientEvents()
|
on = RabbitMQClientEvents()
|
||||||
_stored = StoredState()
|
|
||||||
|
|
||||||
def __init__(self, charm, relation_name):
|
def __init__(self, charm, relation_name, callback):
|
||||||
super().__init__(charm, relation_name)
|
super().__init__(charm, relation_name)
|
||||||
self.charm = charm
|
self.charm = charm
|
||||||
self.relation_name = relation_name
|
self.relation_name = relation_name
|
||||||
|
self.callback = callback
|
||||||
self.framework.observe(
|
self.framework.observe(
|
||||||
self.charm.on[relation_name].relation_joined,
|
self.charm.on[relation_name].relation_joined,
|
||||||
self._on_amqp_relation_joined,
|
self._on_amqp_relation_joined,
|
||||||
@ -255,60 +252,35 @@ class AMQPProvides(Object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _on_amqp_relation_joined(self, event):
|
def _on_amqp_relation_joined(self, event):
|
||||||
"""Handle AMQP joined."""
|
"""Handle RabbitMQ joined."""
|
||||||
logging.debug("RabbitMQAMQPProvides on_joined")
|
logging.debug("RabbitMQRabbitMQProvides on_joined data={}"
|
||||||
|
.format(event.relation.data[event.relation.app]))
|
||||||
self.on.has_amqp_clients.emit()
|
self.on.has_amqp_clients.emit()
|
||||||
|
|
||||||
def _on_amqp_relation_changed(self, event):
|
def _on_amqp_relation_changed(self, event):
|
||||||
"""Handle AMQP changed."""
|
"""Handle RabbitMQ changed."""
|
||||||
logging.debug("RabbitMQAMQPProvides on_changed")
|
logging.debug("RabbitMQRabbitMQProvides on_changed data={}"
|
||||||
|
.format(event.relation.data[event.relation.app]))
|
||||||
# Validate data on the relation
|
# Validate data on the relation
|
||||||
if self.username(event) and self.vhost(event):
|
if self.username(event) and self.vhost(event):
|
||||||
self.on.ready_amqp_clients.emit()
|
self.on.ready_amqp_clients.emit()
|
||||||
if self.charm.unit.is_leader():
|
if self.charm.unit.is_leader():
|
||||||
self.set_amqp_credentials(
|
self.callback(event, self.username(event), self.vhost(event))
|
||||||
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):
|
def _on_amqp_relation_broken(self, event):
|
||||||
"""Handle AMQP broken."""
|
"""Handle RabbitMQ broken."""
|
||||||
logging.debug("RabbitMQAMQPProvides on_departed")
|
logging.debug("RabbitMQRabbitMQProvides on_departed")
|
||||||
# TODO clear data on the relation
|
# TODO clear data on the relation
|
||||||
|
|
||||||
def username(self, event):
|
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")
|
return event.relation.data[event.relation.app].get("username")
|
||||||
|
|
||||||
def vhost(self, event):
|
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")
|
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()
|
|
1
charms/glance-k8s/tests/config.yaml
Symbolic link
1
charms/glance-k8s/tests/config.yaml
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../config.yaml
|
Loading…
x
Reference in New Issue
Block a user