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
34 changes: 33 additions & 1 deletion lib/charms/data_platform_libs/v0/data_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,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 = 59
LIBPATCH = 60

PYDEPS = ["ops>=2.0.0"]

Expand Down Expand Up @@ -5422,6 +5422,8 @@ def __init__(
extra_group_roles: Optional[str] = None,
entity_type: Optional[str] = None,
entity_permissions: Optional[str] = None,
requested_entity_name: Optional[str] = None,
requested_entity_password: Optional[str] = None,
):
"""Manager of OpenSearch client relations."""
super().__init__(
Expand All @@ -5432,6 +5434,9 @@ def __init__(
extra_group_roles,
entity_type,
entity_permissions,
None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better pass keyword arguments instead of just None to make it easier to read/understand.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sharing a secret directly most probably won't be supported in v1, so it is OK to skip, but it is better to use keywords as requested.

requested_entity_name,
requested_entity_password,
)
self.index = index

Expand Down Expand Up @@ -5466,6 +5471,18 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None:
if self.relation_data.entity_permissions:
data["entity-permissions"] = self.relation_data.entity_permissions

if self.relation_data.requested_entity_name:
content = {"entity-name": self.relation_data.requested_entity_name}
if self.relation_data.requested_entity_password:
content["password"] = self.relation_data.requested_entity_password
secret = self.charm.app.add_secret(
content, label=f"{self.model.uuid}-{event.relation.id}-requested-entity"
)
secret.grant(event.relation)

@reneradoi reneradoi Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail in cross-model relations, due to a constraint in Juju: sharing consumer secrets across a cross model relation not supported. For details, see DA264.

Cross-model relations could be more relevant for Opensearch than they are for the current users of this feature, therefor I would recommend to take this into consideration before going forward with this PR.

With #266 a solution was added for the mTLS certificate that could be adapted for the requested_entity_password, too: In case of cross-model relations, store the sensitive information in encrypted form as part of the relation data itself and not as a secret.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For context, when I implemented this originally for Postgresql I followed the same approach as mTLS. Since mTLS itself switched, it makes sense to port this as well. I lack the context to say if it is a strict requirement for Opensearch or not.

if not secret.id:
raise SecretError("Secret helper missing Id")
data["requested-entity-secret"] = secret.id

self.relation_data.update_relation_data(event.relation.id, data)

def _on_secret_changed_event(self, event: SecretChangedEvent):
Expand Down Expand Up @@ -5545,6 +5562,17 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
event.relation, app=event.app, unit=event.unit
)

if (
self.relation_data.local_unit.is_leader()
and self.relation_data.requested_entity_name
and (secret_uri := app_databag.get("requested-entity-secret"))
):
try:
secret = self.framework.model.get_secret(id=secret_uri)
secret.remove_all_revisions()
except ModelError:
logger.debug("Unable to remove helper secret")

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

Expand Down Expand Up @@ -5574,6 +5602,8 @@ def __init__(
extra_group_roles: Optional[str] = None,
entity_type: Optional[str] = None,
entity_permissions: Optional[str] = None,
requested_entity_name: Optional[str] = None,
requested_entity_password: Optional[str] = None,
) -> None:
OpenSearchRequiresData.__init__(
self,
Expand All @@ -5585,6 +5615,8 @@ def __init__(
extra_group_roles,
entity_type,
entity_permissions,
requested_entity_name,
requested_entity_password,
)
OpenSearchRequiresEventHandlers.__init__(self, charm, self)

Expand Down
3 changes: 3 additions & 0 deletions tests/v0/integration/application-charm/src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,14 @@ def __init__(self, *args):

# OpenSearch events

_entity_name, _entity_password = self.requested_entities_secret_content
self.opensearch = OpenSearchRequires(
charm=self,
relation_name="opensearch-client-index",
index="test-index",
extra_user_roles=EXTRA_USER_ROLES_OPENSEARCH,
requested_entity_name=_entity_name,
requested_entity_password=_entity_password,
)
self.framework.observe(self.opensearch.on.index_created, self._on_opensearch_index_created)
self.framework.observe(
Expand Down
Loading