Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 64 additions & 27 deletions auth/lib/charms/data_platform_libs/v0/data_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ def _on_subject_requested(self, event: SubjectRequestedEvent):

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 55
LIBPATCH = 56

PYDEPS = ["ops>=2.0.0"]

Expand Down Expand Up @@ -2071,6 +2071,7 @@ def __init__(
requested_entity_secret: Optional[str] = None,
requested_entity_name: Optional[str] = None,
requested_entity_password: Optional[str] = None,
prefix_matching: Optional[str] = None,
):
"""Manager of base client relations."""
super().__init__(model, relation_name)
Expand All @@ -2081,6 +2082,7 @@ def __init__(
self.requested_entity_secret = requested_entity_secret
self.requested_entity_name = requested_entity_name
self.requested_entity_password = requested_entity_password
self.prefix_matching = prefix_matching

if (
self.requested_entity_secret or self.requested_entity_name
Expand Down Expand Up @@ -3258,6 +3260,14 @@ def requested_entity_secret_content(self) -> Optional[Dict[str, Optional[str]]]:
logger.warning("Invalid requested-entity-secret: no entity name")
return names

@property
def prefix_matching(self) -> Optional[str]:
"""Returns the prefix matching strategy that were requested."""
if not self.relation.app:
return None

return self.relation.data[self.relation.app].get("prefix-matching")


class DatabaseEntityRequestedEvent(DatabaseProvidesEvent, EntityProvidesEvent):
"""Event emitted when a new entity is requested for use on this relation."""
Expand Down Expand Up @@ -3364,6 +3374,16 @@ def version(self) -> Optional[str]:

return self.relation.data[self.relation.app].get("version")

@property
def prefix_databases(self) -> Optional[List[str]]:
"""Returns a list of databases matching a prefix."""
if not self.relation.app:
return None

if prefixed_databases := self.relation.data[self.relation.app].get("prefix-databases"):
return prefixed_databases.split(",")
return []


class DatabaseCreatedEvent(AuthenticationEvent, DatabaseRequiresEvent):
"""Event emitted when a new database is created for use on this relation."""
Expand All @@ -3381,6 +3401,10 @@ class DatabaseReadOnlyEndpointsChangedEvent(AuthenticationEvent, DatabaseRequire
"""Event emitted when the read only endpoints are changed."""


class DatabasePrefixDatabasesChangedEvent(AuthenticationEvent, DatabaseRequiresEvent):
"""Event emitted when the prefix databases are changed."""


class DatabaseRequiresEvents(RequirerCharmEvents):
"""Database events.

Expand All @@ -3391,6 +3415,7 @@ class DatabaseRequiresEvents(RequirerCharmEvents):
database_entity_created = EventSource(DatabaseEntityCreatedEvent)
endpoints_changed = EventSource(DatabaseEndpointsChangedEvent)
read_only_endpoints_changed = EventSource(DatabaseReadOnlyEndpointsChangedEvent)
prefix_databases_changed = EventSource(DatabasePrefixDatabasesChangedEvent)


# Database Provider and Requires
Expand All @@ -3416,6 +3441,18 @@ def set_database(self, relation_id: int, database_name: str) -> None:
"""
self.update_relation_data(relation_id, {"database": database_name})

def set_prefix_databases(self, relation_id: int, databases: List[str]) -> None:
"""Set a coma separated list of databases matching a prefix.

This function writes in the application data bag, therefore,
only the leader unit can call it.

Args:
relation_id: the identifier for a particular relation.
databases: list of database names matching the requested prefix.
"""
self.update_relation_data(relation_id, {"prefix-databases": ",".join(sorted(databases))})

def set_endpoints(self, relation_id: int, connection_strings: str) -> None:
"""Set database primary connections.

Expand Down Expand Up @@ -3588,6 +3625,7 @@ def __init__(
requested_entity_secret: Optional[str] = None,
requested_entity_name: Optional[str] = None,
requested_entity_password: Optional[str] = None,
prefix_matching: Optional[str] = None,
):
"""Manager of database client relations."""
super().__init__(
Expand All @@ -3601,6 +3639,7 @@ def __init__(
requested_entity_secret,
requested_entity_name,
requested_entity_password,
prefix_matching,
)
self.database = database_name
self.relations_aliases = relations_aliases
Expand Down Expand Up @@ -3700,6 +3739,10 @@ def __init__(
f"{relation_alias}_read_only_endpoints_changed",
DatabaseReadOnlyEndpointsChangedEvent,
)
self.on.define_event(
f"{relation_alias}_prefix_databases_changed",
DatabasePrefixDatabasesChangedEvent,
)

def _on_secret_changed_event(self, event: SecretChangedEvent):
"""Event notifying about a new value of a secret."""
Expand Down Expand Up @@ -3792,6 +3835,8 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None:
event_data["entity-permissions"] = self.relation_data.entity_permissions
if self.relation_data.requested_entity_secret:
event_data["requested-entity-secret"] = self.relation_data.requested_entity_secret
if self.relation_data.prefix_matching:
event_data["prefix-matching"] = self.relation_data.prefix_matching

# Create helper secret if needed
if (
Expand Down Expand Up @@ -3884,32 +3929,22 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
# To avoid unnecessary application restarts do not trigger other events.
return

# Emit an endpoints changed event if the database
# added or changed this info in the relation databag.
if "endpoints" in diff.added or "endpoints" in diff.changed:
# Emit the default event (the one without an alias).
logger.info("endpoints changed on %s", datetime.now())
getattr(self.on, "endpoints_changed").emit(
event.relation, app=event.app, unit=event.unit
)

# Emit the aliased event (if any).
self._emit_aliased_event(event, "endpoints_changed")

# To avoid unnecessary application restarts do not trigger other events.
return

# Emit a read only endpoints changed event if the database
# added or changed this info in the relation databag.
if "read-only-endpoints" in diff.added or "read-only-endpoints" in diff.changed:
# Emit the default event (the one without an alias).
logger.info("read-only-endpoints changed on %s", datetime.now())
getattr(self.on, "read_only_endpoints_changed").emit(
event.relation, app=event.app, unit=event.unit
)

# Emit the aliased event (if any).
self._emit_aliased_event(event, "read_only_endpoints_changed")
for key, event_name in [
("endpoints", "endpoints_changed"),
("read-only-endpoints", "read_only_endpoints_changed"),
("prefix-databases", "prefix_databases_changed"),
]:
# Emit a change event if the key changed.
if key in diff.added or key in diff.changed:
# Emit the default event (the one without an alias).
logger.info("%s changed on %s", key, datetime.now())
getattr(self.on, event_name).emit(event.relation, app=event.app, unit=event.unit)

# Emit the aliased event (if any).
self._emit_aliased_event(event, event_name)

# To avoid unnecessary application restarts do not trigger other events.
return


class DatabaseRequires(DatabaseRequirerData, DatabaseRequirerEventHandlers):
Expand All @@ -3930,6 +3965,7 @@ def __init__(
requested_entity_secret: Optional[str] = None,
requested_entity_name: Optional[str] = None,
requested_entity_password: Optional[str] = None,
prefix_matching: Optional[str] = None,
):
DatabaseRequirerData.__init__(
self,
Expand All @@ -3946,6 +3982,7 @@ def __init__(
requested_entity_secret,
requested_entity_name,
requested_entity_password,
prefix_matching,
)
DatabaseRequirerEventHandlers.__init__(self, charm, self)

Expand Down
Loading
Loading