Support ceph-access relation
Change-Id: I05872c91bd68ef5a9836a6a4a229138a8ebaabf3 Signed-off-by: Liam Young <liam.young@canonical.com>
This commit is contained in:
parent
b68d398fbf
commit
947c2b34b2
@ -0,0 +1,266 @@
|
|||||||
|
"""CephAccess Provides and Requires module.
|
||||||
|
|
||||||
|
This library contains the Requires and Provides classes for handling
|
||||||
|
the ceph-access interface.
|
||||||
|
|
||||||
|
Import `CephAccessRequires` in your charm, with the charm object and the
|
||||||
|
relation name:
|
||||||
|
- self
|
||||||
|
- "ceph_access"
|
||||||
|
|
||||||
|
Three events are also available to respond to:
|
||||||
|
- connected
|
||||||
|
- ready
|
||||||
|
- goneaway
|
||||||
|
|
||||||
|
A basic example showing the usage of this relation follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
from charms.cinder_ceph_k8s.v0.ceph_access import CephAccessRequires
|
||||||
|
|
||||||
|
class CephAccessClientCharm(CharmBase):
|
||||||
|
def __init__(self, *args):
|
||||||
|
super().__init__(*args)
|
||||||
|
# CephAccess Requires
|
||||||
|
self.ceph_access = CephAccessRequires(
|
||||||
|
self,
|
||||||
|
relation_name="ceph_access",
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.ceph_access.on.connected, self._on_ceph_access_connected)
|
||||||
|
self.framework.observe(
|
||||||
|
self.ceph_access.on.ready, self._on_ceph_access_ready)
|
||||||
|
self.framework.observe(
|
||||||
|
self.ceph_access.on.goneaway, self._on_ceph_access_goneaway)
|
||||||
|
|
||||||
|
def _on_ceph_access_connected(self, event):
|
||||||
|
'''React to the CephAccess connected event.
|
||||||
|
|
||||||
|
This event happens when n CephAccess relation is added to the
|
||||||
|
model before credentials etc have been provided.
|
||||||
|
'''
|
||||||
|
# Do something before the relation is complete
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _on_ceph_access_ready(self, event):
|
||||||
|
'''React to the CephAccess ready event.
|
||||||
|
|
||||||
|
This event happens when an CephAccess relation is removed.
|
||||||
|
'''
|
||||||
|
# IdentityService Relation has goneaway. shutdown services or suchlike
|
||||||
|
pass
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The unique Charmhub library identifier, never change it
|
||||||
|
LIBID = "7fa8d4f8407c4f31ab1deb51c0c046f1"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from ops.model import (
|
||||||
|
Relation,
|
||||||
|
SecretNotFoundError,
|
||||||
|
)
|
||||||
|
from ops.framework import (
|
||||||
|
EventBase,
|
||||||
|
ObjectEvents,
|
||||||
|
EventSource,
|
||||||
|
Object,
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class CephAccessConnectedEvent(EventBase):
|
||||||
|
"""CephAccess connected Event."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CephAccessReadyEvent(EventBase):
|
||||||
|
"""CephAccess ready for use Event."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CephAccessGoneAwayEvent(EventBase):
|
||||||
|
"""CephAccess relation has gone-away Event"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CephAccessServerEvents(ObjectEvents):
|
||||||
|
"""Events class for `on`"""
|
||||||
|
|
||||||
|
connected = EventSource(CephAccessConnectedEvent)
|
||||||
|
ready = EventSource(CephAccessReadyEvent)
|
||||||
|
goneaway = EventSource(CephAccessGoneAwayEvent)
|
||||||
|
|
||||||
|
|
||||||
|
class CephAccessRequires(Object):
|
||||||
|
"""
|
||||||
|
CephAccessRequires class
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
on = CephAccessServerEvents()
|
||||||
|
|
||||||
|
def __init__(self, charm, 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_joined,
|
||||||
|
self._on_ceph_access_relation_joined,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_changed,
|
||||||
|
self._on_ceph_access_relation_changed,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_departed,
|
||||||
|
self._on_ceph_access_relation_changed,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_broken,
|
||||||
|
self._on_ceph_access_relation_broken,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _ceph_access_rel(self) -> Relation:
|
||||||
|
"""The CephAccess relation."""
|
||||||
|
return self.framework.model.get_relation(self.relation_name)
|
||||||
|
|
||||||
|
def get_remote_app_data(self, key: str) -> str:
|
||||||
|
"""Return the value for the given key from remote app data."""
|
||||||
|
data = self._ceph_access_rel.data[self._ceph_access_rel.app]
|
||||||
|
return data.get(key)
|
||||||
|
|
||||||
|
def _on_ceph_access_relation_joined(self, event):
|
||||||
|
"""CephAccess relation joined."""
|
||||||
|
logging.debug("CephAccess on_joined")
|
||||||
|
self.on.connected.emit()
|
||||||
|
|
||||||
|
def _on_ceph_access_relation_changed(self, event):
|
||||||
|
"""CephAccess relation changed."""
|
||||||
|
logging.debug("CephAccess on_changed")
|
||||||
|
try:
|
||||||
|
if self.ready:
|
||||||
|
self.on.ready.emit()
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _on_ceph_access_relation_broken(self, event):
|
||||||
|
"""CephAccess relation broken."""
|
||||||
|
logging.debug("CephAccess on_broken")
|
||||||
|
self.on.goneaway.emit()
|
||||||
|
|
||||||
|
def _retrieve_secret(self):
|
||||||
|
try:
|
||||||
|
credentials_id = self.get_remote_app_data('access-credentials')
|
||||||
|
if not credentials_id:
|
||||||
|
return None
|
||||||
|
credentials = self.charm.model.get_secret(id=credentials_id)
|
||||||
|
return credentials
|
||||||
|
except SecretNotFoundError:
|
||||||
|
logger.warning(f"Secret {credentials_id} not found")
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ceph_access_data(self):
|
||||||
|
"""Return the service_password."""
|
||||||
|
secret = self._retrieve_secret()
|
||||||
|
if not secret:
|
||||||
|
return {}
|
||||||
|
return secret.get_content()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ready(self) -> str:
|
||||||
|
"""Return the service_password."""
|
||||||
|
return all(k in self.ceph_access_data for k in ["uuid", "key"])
|
||||||
|
|
||||||
|
class HasCephAccessClientsEvent(EventBase):
|
||||||
|
"""Has CephAccessClients Event."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ReadyCephAccessClientsEvent(EventBase):
|
||||||
|
"""Has CephAccessClients Event."""
|
||||||
|
|
||||||
|
def __init__(self, handle, relation_id):
|
||||||
|
super().__init__(handle)
|
||||||
|
self.relation_id = relation_id
|
||||||
|
|
||||||
|
def snapshot(self):
|
||||||
|
return {"relation_id": self.relation_id}
|
||||||
|
|
||||||
|
def restore(self, snapshot):
|
||||||
|
super().restore(snapshot)
|
||||||
|
self.relation_id = snapshot["relation_id"]
|
||||||
|
|
||||||
|
class CephAccessClientEvents(ObjectEvents):
|
||||||
|
"""Events class for `on`"""
|
||||||
|
|
||||||
|
has_ceph_access_clients = EventSource(HasCephAccessClientsEvent)
|
||||||
|
ready_ceph_access_clients = EventSource(ReadyCephAccessClientsEvent)
|
||||||
|
|
||||||
|
|
||||||
|
class CephAccessProvides(Object):
|
||||||
|
"""
|
||||||
|
CephAccessProvides class
|
||||||
|
"""
|
||||||
|
|
||||||
|
on = CephAccessClientEvents()
|
||||||
|
|
||||||
|
def __init__(self, charm, relation_name):
|
||||||
|
super().__init__(charm, relation_name)
|
||||||
|
self.charm = charm
|
||||||
|
self.relation_name = relation_name
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_joined,
|
||||||
|
self._on_ceph_access_relation_joined,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_changed,
|
||||||
|
self._on_ceph_access_relation_changed,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_broken,
|
||||||
|
self._on_ceph_access_relation_broken,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _on_ceph_access_relation_joined(self, event):
|
||||||
|
"""Handle CephAccess joined."""
|
||||||
|
logging.debug("CephAccess on_joined")
|
||||||
|
self.on.has_ceph_access_clients.emit()
|
||||||
|
|
||||||
|
def _on_ceph_access_relation_changed(self, event):
|
||||||
|
"""Handle CephAccess joined."""
|
||||||
|
logging.debug("CephAccess on_changed")
|
||||||
|
self.on.ready_ceph_access_clients.emit(event.relation.id)
|
||||||
|
|
||||||
|
def _on_ceph_access_relation_broken(self, event):
|
||||||
|
"""Handle CephAccess broken."""
|
||||||
|
logging.debug("CephAccessProvides on_broken")
|
||||||
|
|
||||||
|
def set_ceph_access_credentials(self, relation_name: int,
|
||||||
|
relation_id: str,
|
||||||
|
access_credentials: str):
|
||||||
|
|
||||||
|
logging.debug("Setting ceph_access connection information.")
|
||||||
|
_ceph_access_rel = None
|
||||||
|
for relation in self.framework.model.relations[relation_name]:
|
||||||
|
if relation.id == relation_id:
|
||||||
|
_ceph_access_rel = relation
|
||||||
|
if not _ceph_access_rel:
|
||||||
|
# Relation has disappeared so skip send of data
|
||||||
|
return
|
||||||
|
app_data = _ceph_access_rel.data[self.charm.app]
|
||||||
|
logging.debug(access_credentials)
|
||||||
|
app_data["access-credentials"] = access_credentials
|
@ -20,6 +20,9 @@ requires:
|
|||||||
ceilometer-service:
|
ceilometer-service:
|
||||||
interface: ceilometer
|
interface: ceilometer
|
||||||
optional: true
|
optional: true
|
||||||
|
ceph-access:
|
||||||
|
interface: cinder-ceph-key
|
||||||
|
optional: true
|
||||||
|
|
||||||
provides:
|
provides:
|
||||||
cos-agent:
|
cos-agent:
|
||||||
|
@ -215,6 +215,7 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
|
|||||||
sb_connection_strs = list(contexts.ovsdb_cms.db_ingress_sb_connection_strs)
|
sb_connection_strs = list(contexts.ovsdb_cms.db_ingress_sb_connection_strs)
|
||||||
if not sb_connection_strs:
|
if not sb_connection_strs:
|
||||||
raise AttributeError(name="ovsdb southbound ingress string")
|
raise AttributeError(name="ovsdb southbound ingress string")
|
||||||
|
|
||||||
snap_data = {
|
snap_data = {
|
||||||
"compute.cpu-mode": "host-model",
|
"compute.cpu-mode": "host-model",
|
||||||
"compute.spice-proxy-address": config("ip-address") or local_ip,
|
"compute.spice-proxy-address": config("ip-address") or local_ip,
|
||||||
@ -252,8 +253,20 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
|
|||||||
}
|
}
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
raise sunbeam_guard.WaitingExceptionError("Data missing: {}".format(e.name))
|
raise sunbeam_guard.WaitingExceptionError("Data missing: {}".format(e.name))
|
||||||
|
|
||||||
# Handle optional config contexts
|
# Handle optional config contexts
|
||||||
|
try:
|
||||||
|
if contexts.ceph_access.uuid:
|
||||||
|
snap_data.update(
|
||||||
|
{
|
||||||
|
"compute.rbd-user": "nova",
|
||||||
|
"compute.rbd-secret-uuid": contexts.ceph_access.uuid,
|
||||||
|
"compute.rbd-key": contexts.ceph_access.key,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
# If the relation has been removed it is probably less disruptive to leave the
|
||||||
|
# rbd setting in the snap rather than unsetting them.
|
||||||
|
logger.debug("ceph_access relation not integrated")
|
||||||
try:
|
try:
|
||||||
if contexts.ceilometer_service.telemetry_secret:
|
if contexts.ceilometer_service.telemetry_secret:
|
||||||
snap_data.update(
|
snap_data.update(
|
||||||
|
@ -76,6 +76,18 @@ class TestCharm(test_utils.CharmTestCase):
|
|||||||
"private-address": "10.20.21.10",
|
"private-address": "10.20.21.10",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
ceph_rel_id = self.harness.add_relation("ceph-access", "cinder-ceph")
|
||||||
|
self.harness.add_relation_unit(ceph_rel_id, "cinder-ceph/0")
|
||||||
|
|
||||||
|
credentials_content = {"uuid": "ddd", "key": "eee"}
|
||||||
|
credentials_id = self.harness.add_model_secret("cinder-ceph", credentials_content)
|
||||||
|
|
||||||
|
self.harness.grant_secret(credentials_id, self.harness.charm.app.name)
|
||||||
|
self.harness.update_relation_data(
|
||||||
|
ceph_rel_id,
|
||||||
|
"cinder-ceph",
|
||||||
|
{"access-credentials": credentials_id},
|
||||||
|
)
|
||||||
|
|
||||||
def test_mandatory_relations(self):
|
def test_mandatory_relations(self):
|
||||||
"""Test all the charms relations."""
|
"""Test all the charms relations."""
|
||||||
@ -101,6 +113,9 @@ class TestCharm(test_utils.CharmTestCase):
|
|||||||
"compute.cpu-mode": "host-model",
|
"compute.cpu-mode": "host-model",
|
||||||
"compute.spice-proxy-address": "10.0.0.10",
|
"compute.spice-proxy-address": "10.0.0.10",
|
||||||
"compute.virt-type": "kvm",
|
"compute.virt-type": "kvm",
|
||||||
|
"compute.rbd-user": "nova",
|
||||||
|
"compute.rbd-secret-uuid": "ddd",
|
||||||
|
"compute.rbd-key": "eee",
|
||||||
"credentials.ovn-metadata-proxy-shared-secret": metadata,
|
"credentials.ovn-metadata-proxy-shared-secret": metadata,
|
||||||
"identity.admin-role": None,
|
"identity.admin-role": None,
|
||||||
"identity.auth-url": "http://10.153.2.45:80/openstack-keystone",
|
"identity.auth-url": "http://10.153.2.45:80/openstack-keystone",
|
||||||
@ -173,6 +188,9 @@ class TestCharm(test_utils.CharmTestCase):
|
|||||||
"compute.cpu-mode": "host-model",
|
"compute.cpu-mode": "host-model",
|
||||||
"compute.spice-proxy-address": "10.0.0.10",
|
"compute.spice-proxy-address": "10.0.0.10",
|
||||||
"compute.virt-type": "kvm",
|
"compute.virt-type": "kvm",
|
||||||
|
"compute.rbd-user": "nova",
|
||||||
|
"compute.rbd-secret-uuid": "ddd",
|
||||||
|
"compute.rbd-key": "eee",
|
||||||
"credentials.ovn-metadata-proxy-shared-secret": metadata,
|
"credentials.ovn-metadata-proxy-shared-secret": metadata,
|
||||||
"identity.admin-role": None,
|
"identity.admin-role": None,
|
||||||
"identity.auth-url": "http://10.153.2.45:80/openstack-keystone",
|
"identity.auth-url": "http://10.153.2.45:80/openstack-keystone",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user