Skip to content

Commit 263fd55

Browse files
authored
feat: authentication updated on new tls cert (#246)
1 parent 97d10af commit 263fd55

File tree

5 files changed

+58
-4
lines changed

5 files changed

+58
-4
lines changed

lib/charms/data_platform_libs/v1/data_interfaces.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def _on_resource_requested(self, event: ResourceRequestedEvent) -> None:
309309

310310
# Increment this PATCH version before using `charmcraft publish-lib` or reset
311311
# to 0 if you are raising the major API version
312-
LIBPATCH = 0
312+
LIBPATCH = 1
313313

314314
PYDEPS = ["ops>=2.0.0", "pydantic>=2.11"]
315315

@@ -728,7 +728,7 @@ def serialize_model(self, handler: SerializerFunctionWrapHandler, info: Serializ
728728

729729
value = getattr(self, field)
730730

731-
if value and not isinstance(value, str):
731+
if (value is not None) and not isinstance(value, str):
732732
value = json.dumps(value)
733733

734734
if secret is None:
@@ -864,7 +864,7 @@ def serialize_model(
864864

865865
value = getattr(self, field)
866866

867-
if value and not isinstance(value, str):
867+
if (value is not None) and not isinstance(value, str):
868868
value = json.dumps(value)
869869

870870
if secret is None:
@@ -2952,3 +2952,11 @@ def _handle_event(
29522952
)
29532953
self._emit_aliased_event(event, "read_only_endpoints_changed", response)
29542954
return
2955+
2956+
if "secret-tls" in _diff.added or "secret-tls" in _diff.changed:
2957+
logger.info(f"auth updated for {response.resource} at {datetime.now()}")
2958+
getattr(self.on, "authentication_updated").emit(
2959+
event.relation, app=event.app, unit=event.unit, response=response
2960+
)
2961+
self._emit_aliased_event(event, "authentication_updated", response)
2962+
return

tests/v1/integration/application-charm/src/charm.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from pydantic import Field
1919

2020
from charms.data_platform_libs.v1.data_interfaces import (
21+
AuthenticationUpdatedEvent,
2122
ExtraSecretStr,
2223
KafkaRequestModel,
2324
KafkaResponseModel,
@@ -93,6 +94,10 @@ def __init__(self, *args):
9394
self.first_database_roles.on.resource_entity_created,
9495
self._on_first_database_entity_created,
9596
)
97+
self.framework.observe(
98+
self.first_database.on.authentication_updated,
99+
self._on_first_database_auth_updated,
100+
)
96101

97102
# Events related to the second database that is requested
98103
# (these events are defined in the database requires charm library).
@@ -386,6 +391,12 @@ def _on_first_database_entity_created(self, event: ResourceEntityCreatedEvent) -
386391
logger.info(f"first database entity credentials: {event.response.entity_name}")
387392
self.unit.status = ActiveStatus("received entity credentials of the first database")
388393

394+
def _on_first_database_auth_updated(self, event: AuthenticationUpdatedEvent) -> None:
395+
"""Event triggered when a database entity was created for this application."""
396+
# Retrieve the credentials using the charm library.
397+
logger.info(f"first database tls credentials: {event.response.tls}")
398+
self.unit.status = ActiveStatus("first_database_authentication_updated")
399+
389400
# Second database events observers.
390401
def _on_second_database_created(self, event: ResourceCreatedEvent) -> None:
391402
"""Event triggered when a database was created for this application."""

tests/v1/integration/database-charm/actions.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
change-admin-password:
44
description: Change the admin password to a new, generated value
55

6+
set-tls:
7+
description: Set TLS field in the relation
8+
69
set-secret:
710
description: Change the value of a particular secret
811
params:
@@ -138,3 +141,4 @@ get-other-peer-relation-field:
138141
field:
139142
type: string
140143
description: Relation field
144+

tests/v1/integration/database-charm/src/charm.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ def __init__(self, *args):
139139
self.on.get_other_peer_relation_field_action, self._on_get_other_peer_relation_field
140140
)
141141

142+
self.framework.observe(self.on.set_tls_action, self._on_set_tls_action)
143+
142144
@property
143145
def peer_relation(self) -> Optional[Relation]:
144146
"""The cluster peer relation."""
@@ -258,12 +260,19 @@ def _on_resource_requested(self, event: ResourceRequestedEvent) -> None:
258260
password=password,
259261
username=username,
260262
endpoints=f"{self.model.get_binding('database').network.bind_address}:5432",
261-
tls=False,
262263
version=version,
263264
)
264265
self.database.set_response(event.relation.id, response)
265266
self.unit.status = ActiveStatus()
266267

268+
def _on_set_tls_action(self, event: ActionEvent):
269+
for relation in self.database.interface.relations:
270+
model = self.database.interface.build_model(relation.id, DataContract)
271+
for request in model.requests:
272+
request.tls = True
273+
request.tls_ca = "deadbeef"
274+
self.database.interface.write_model(relation.id, model)
275+
267276
def _on_resource_entity_requested(self, event: ResourceEntityRequestedEvent) -> None:
268277
"""Event triggered when a new database entity is requested."""
269278
self.unit.status = MaintenanceStatus("creating entity")

tests/v1/integration/test_charm.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,28 @@ async def test_postgresql_plugin(ops_test: OpsTest):
669669
assert action.results.get("plugin-status") == "enabled"
670670

671671

672+
@pytest.mark.abort_on_fail
673+
async def test_tls_integration_after_initial_integration(ops_test: OpsTest):
674+
"""Test that adding TLS to the database after the initial integration does trigger an auth updated event in the client."""
675+
leader_id = await get_leader_id(ops_test, DATABASE_APP_NAME)
676+
unit_name = f"{DATABASE_APP_NAME}/{leader_id}"
677+
678+
action = await ops_test.model.units.get(unit_name).run_action("set-tls")
679+
await action.wait()
680+
681+
app_id = await get_leader_id(ops_test, APPLICATION_APP_NAME)
682+
app_unit_name = f"{APPLICATION_APP_NAME}/{app_id}"
683+
684+
await ops_test.model.wait_for_idle(
685+
apps=[APPLICATION_APP_NAME, DATABASE_APP_NAME], status="active"
686+
)
687+
688+
assert (
689+
ops_test.model.units.get(app_unit_name).workload_status_message
690+
== "first_database_authentication_updated"
691+
)
692+
693+
672694
async def test_two_applications_dont_share_the_same_relation_data(
673695
ops_test: OpsTest, application_charm
674696
):

0 commit comments

Comments
 (0)