@@ -331,7 +331,7 @@ def _on_topic_requested(self, event: TopicRequestedEvent):
331
331
332
332
# Increment this PATCH version before using `charmcraft publish-lib` or reset
333
333
# to 0 if you are raising the major API version
334
- LIBPATCH = 45
334
+ LIBPATCH = 47
335
335
336
336
PYDEPS = ["ops>=2.0.0" ]
337
337
@@ -989,11 +989,7 @@ def __init__(
989
989
@property
990
990
def relations (self ) -> List [Relation ]:
991
991
"""The list of Relation instances associated with this relation_name."""
992
- return [
993
- relation
994
- for relation in self ._model .relations [self .relation_name ]
995
- if self ._is_relation_active (relation )
996
- ]
992
+ return self ._model .relations [self .relation_name ]
997
993
998
994
@property
999
995
def secrets_enabled (self ):
@@ -1271,15 +1267,6 @@ def _legacy_apply_on_delete(self, fields: List[str]) -> None:
1271
1267
1272
1268
# Internal helper methods
1273
1269
1274
- @staticmethod
1275
- def _is_relation_active (relation : Relation ):
1276
- """Whether the relation is active based on contained data."""
1277
- try :
1278
- _ = repr (relation .data )
1279
- return True
1280
- except (RuntimeError , ModelError ):
1281
- return False
1282
-
1283
1270
@staticmethod
1284
1271
def _is_secret_field (field : str ) -> bool :
1285
1272
"""Is the field in question a secret reference (URI) field or not?"""
@@ -2582,7 +2569,7 @@ def __init__(
2582
2569
2583
2570
2584
2571
################################################################################
2585
- # Cross-charm Relatoins Data Handling and Evenets
2572
+ # Cross-charm Relations Data Handling and Events
2586
2573
################################################################################
2587
2574
2588
2575
# Generic events
@@ -3281,7 +3268,7 @@ def __init__(
3281
3268
# Kafka Events
3282
3269
3283
3270
3284
- class KafkaProvidesEvent (RelationEvent ):
3271
+ class KafkaProvidesEvent (RelationEventWithSecret ):
3285
3272
"""Base class for Kafka events."""
3286
3273
3287
3274
@property
@@ -3300,6 +3287,40 @@ def consumer_group_prefix(self) -> Optional[str]:
3300
3287
3301
3288
return self .relation .data [self .relation .app ].get ("consumer-group-prefix" )
3302
3289
3290
+ @property
3291
+ def mtls_cert (self ) -> Optional [str ]:
3292
+ """Returns TLS cert of the client."""
3293
+ if not self .relation .app :
3294
+ return None
3295
+
3296
+ if not self .secrets_enabled :
3297
+ raise SecretsUnavailableError ("Secrets unavailable on current Juju version" )
3298
+
3299
+ secret_field = f"{ PROV_SECRET_PREFIX } { SECRET_GROUPS .MTLS } "
3300
+ if secret_uri := self .relation .data [self .app ].get (secret_field ):
3301
+ secret = self .framework .model .get_secret (id = secret_uri )
3302
+ content = secret .get_content (refresh = True )
3303
+ if content :
3304
+ return content .get ("mtls-cert" )
3305
+
3306
+
3307
+ class KafkaClientMtlsCertUpdatedEvent (KafkaProvidesEvent ):
3308
+ """Event emitted when the mtls relation is updated."""
3309
+
3310
+ def __init__ (self , handle , relation , old_mtls_cert : Optional [str ] = None , app = None , unit = None ):
3311
+ super ().__init__ (handle , relation , app , unit )
3312
+
3313
+ self .old_mtls_cert = old_mtls_cert
3314
+
3315
+ def snapshot (self ):
3316
+ """Return a snapshot of the event."""
3317
+ return super ().snapshot () | {"old_mtls_cert" : self .old_mtls_cert }
3318
+
3319
+ def restore (self , snapshot ):
3320
+ """Restore the event from a snapshot."""
3321
+ super ().restore (snapshot )
3322
+ self .old_mtls_cert = snapshot ["old_mtls_cert" ]
3323
+
3303
3324
3304
3325
class TopicRequestedEvent (KafkaProvidesEvent , ExtraRoleEvent ):
3305
3326
"""Event emitted when a new topic is requested for use on this relation."""
@@ -3312,6 +3333,7 @@ class KafkaProvidesEvents(CharmEvents):
3312
3333
"""
3313
3334
3314
3335
topic_requested = EventSource (TopicRequestedEvent )
3336
+ mtls_cert_updated = EventSource (KafkaClientMtlsCertUpdatedEvent )
3315
3337
3316
3338
3317
3339
class KafkaRequiresEvent (RelationEvent ):
@@ -3429,6 +3451,13 @@ def __init__(self, charm: CharmBase, relation_data: KafkaProviderData) -> None:
3429
3451
def _on_relation_changed_event (self , event : RelationChangedEvent ) -> None :
3430
3452
"""Event emitted when the relation has changed."""
3431
3453
super ()._on_relation_changed_event (event )
3454
+
3455
+ new_data_keys = list (event .relation .data [event .app ].keys ())
3456
+ if any (newval for newval in new_data_keys if self .relation_data ._is_secret_field (newval )):
3457
+ self .relation_data ._register_secrets_to_relation (event .relation , new_data_keys )
3458
+
3459
+ getattr (self .on , "mtls_cert_updated" ).emit (event .relation , app = event .app , unit = event .unit )
3460
+
3432
3461
# Leader only
3433
3462
if not self .relation_data .local_unit .is_leader ():
3434
3463
return
@@ -3443,6 +3472,33 @@ def _on_relation_changed_event(self, event: RelationChangedEvent) -> None:
3443
3472
event .relation , app = event .app , unit = event .unit
3444
3473
)
3445
3474
3475
+ def _on_secret_changed_event (self , event : SecretChangedEvent ):
3476
+ """Event notifying about a new value of a secret."""
3477
+ if not event .secret .label :
3478
+ return
3479
+
3480
+ relation = self .relation_data ._relation_from_secret_label (event .secret .label )
3481
+ if not relation :
3482
+ logging .info (
3483
+ f"Received secret { event .secret .label } but couldn't parse, seems irrelevant"
3484
+ )
3485
+ return
3486
+
3487
+ if relation .app == self .charm .app :
3488
+ logging .info ("Secret changed event ignored for Secret Owner" )
3489
+
3490
+ remote_unit = None
3491
+ for unit in relation .units :
3492
+ if unit .app != self .charm .app :
3493
+ remote_unit = unit
3494
+
3495
+ old_mtls_cert = event .secret .get_content ().get ("mtls-cert" )
3496
+ # mtls-cert is the only secret that can be updated
3497
+ logger .info ("mtls-cert updated" )
3498
+ getattr (self .on , "mtls_cert_updated" ).emit (
3499
+ relation , app = relation .app , unit = remote_unit , old_mtls_cert = old_mtls_cert
3500
+ )
3501
+
3446
3502
3447
3503
class KafkaProvides (KafkaProviderData , KafkaProviderEventHandlers ):
3448
3504
"""Provider-side of the Kafka relation."""
@@ -3463,11 +3519,13 @@ def __init__(
3463
3519
extra_user_roles : Optional [str ] = None ,
3464
3520
consumer_group_prefix : Optional [str ] = None ,
3465
3521
additional_secret_fields : Optional [List [str ]] = [],
3522
+ mtls_cert : Optional [str ] = None ,
3466
3523
):
3467
3524
"""Manager of Kafka client relations."""
3468
3525
super ().__init__ (model , relation_name , extra_user_roles , additional_secret_fields )
3469
3526
self .topic = topic
3470
3527
self .consumer_group_prefix = consumer_group_prefix or ""
3528
+ self .mtls_cert = mtls_cert
3471
3529
3472
3530
@property
3473
3531
def topic (self ):
@@ -3481,6 +3539,15 @@ def topic(self, value):
3481
3539
raise ValueError (f"Error on topic '{ value } ', cannot be a wildcard." )
3482
3540
self ._topic = value
3483
3541
3542
+ def set_mtls_cert (self , relation_id : int , mtls_cert : str ) -> None :
3543
+ """Set the mtls cert in the application relation databag / secret.
3544
+
3545
+ Args:
3546
+ relation_id: the identifier for a particular relation.
3547
+ mtls_cert: mtls cert.
3548
+ """
3549
+ self .update_relation_data (relation_id , {"mtls-cert" : mtls_cert })
3550
+
3484
3551
3485
3552
class KafkaRequirerEventHandlers (RequirerEventHandlers ):
3486
3553
"""Requires-side of the Kafka relation."""
@@ -3502,6 +3569,9 @@ def _on_relation_created_event(self, event: RelationCreatedEvent) -> None:
3502
3569
# Sets topic, extra user roles, and "consumer-group-prefix" in the relation
3503
3570
relation_data = {"topic" : self .relation_data .topic }
3504
3571
3572
+ if self .relation_data .mtls_cert :
3573
+ relation_data ["mtls-cert" ] = self .relation_data .mtls_cert
3574
+
3505
3575
if self .relation_data .extra_user_roles :
3506
3576
relation_data ["extra-user-roles" ] = self .relation_data .extra_user_roles
3507
3577
@@ -3560,15 +3630,17 @@ def __init__(
3560
3630
extra_user_roles : Optional [str ] = None ,
3561
3631
consumer_group_prefix : Optional [str ] = None ,
3562
3632
additional_secret_fields : Optional [List [str ]] = [],
3633
+ mtls_cert : Optional [str ] = None ,
3563
3634
) -> None :
3564
3635
KafkaRequirerData .__init__ (
3565
3636
self ,
3566
3637
charm .model ,
3567
3638
relation_name ,
3568
3639
topic ,
3569
- extra_user_roles ,
3570
- consumer_group_prefix ,
3571
- additional_secret_fields ,
3640
+ extra_user_roles = extra_user_roles ,
3641
+ consumer_group_prefix = consumer_group_prefix ,
3642
+ additional_secret_fields = additional_secret_fields ,
3643
+ mtls_cert = mtls_cert ,
3572
3644
)
3573
3645
KafkaRequirerEventHandlers .__init__ (self , charm , self )
3574
3646
0 commit comments